Skip to content

Commit 9f08987

Browse files
committed
Detect characters between elements in server.xml
1 parent 0dfd93c commit 9f08987

File tree

2 files changed

+85
-7
lines changed

2 files changed

+85
-7
lines changed

dev/com.ibm.ws.config/resources/com/ibm/ws/config/internal/resources/ConfigMessages.nlsprops

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
###############################################################################
2-
# Copyright (c) 2010, 2020 IBM Corporation and others.
2+
# Copyright (c) 2010, 2025 IBM Corporation and others.
33
# All rights reserved. This program and the accompanying materials
44
# are made available under the terms of the Eclipse Public License 2.0
55
# which accompanies this distribution, and is available at
@@ -498,5 +498,9 @@ error.config.root.deleted=CWWKG0110E: A configuration update was detected, but t
498498
error.config.root.deleted.explanation=The server.xml file was deleted. To cause no disruptions to running apps, no configuration changes are made.
499499
error.config.root.deleted.useraction=Add the server.xml file back to the server.
500500

501+
error.potential.malformed.element=CWWKG0111E: Potential malformed XML element detected in configuration: [{0}] at line {1} in {2}. This text appears to be an XML element but is missing the opening angle bracket (<). Verify that the syntax is correct.
502+
error.potential.malformed.element.explanation=The configuration parser detected text that might be a malformed XML element. This error typically occurs when an element is missing its opening angle bracket (<).
503+
error.potential.malformed.element.useraction=Check the configuration file at the specified line and ensure that all XML elements start with an opening angle bracket (<).
504+
501505
# Non-TR message
502506
error.invalidOCDRef=ERROR: Metatype PID [{0}] specifies non-existent object class definition ID [{1}]

dev/com.ibm.ws.config/src/com/ibm/ws/config/xml/internal/XMLConfigParser.java

Lines changed: 80 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ private boolean parseServerConfiguration(DepthAwareXMLStreamReader parser, Strin
261261
}
262262
// If we get here, there is a single element in the file and it is not <server> or <client>
263263
logError(ThrowBehavior.ALWAYS_THROW_EXCEPTION, "error.root.must.be.server", docLocation, processType);
264-
return false; // Dead code because of the always-throw above, but we must please the compiler.
264+
return false; // Unreachable: ALWAYS_THROW_EXCEPTION guarantees an exception, but we must please the compiler.
265265

266266
} catch (XMLStreamException e) {
267267
throw new ConfigParserException(e);
@@ -329,7 +329,35 @@ private void parseServer(DepthAwareXMLStreamReader parser, String docLocation, B
329329
Tr.debug(tc, "parseServer: event=" + eventName + " (" + event + "), depth=" + depth + ", location=" + parser.getLocation().getLineNumber());
330330
}
331331

332-
if (event == XMLStreamConstants.START_ELEMENT) {
332+
if (event == XMLStreamConstants.CHARACTERS) {
333+
// Check for potential malformed XML elements
334+
String text = parser.getText();
335+
336+
// Debug logging - log ALL CHARACTERS events
337+
if (tc.isDebugEnabled()) {
338+
String displayText = text != null ? text.replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t") : "null";
339+
Tr.debug(tc, "CHARACTERS event, text length=" + (text != null ? text.length() : 0) +
340+
", trimmed length=" + (text != null ? text.trim().length() : 0) +
341+
", text=[" + displayText + "]");
342+
}
343+
344+
if (text != null && text.trim().length() > 0) {
345+
String trimmed = text.trim();
346+
347+
// Skip invisible Unicode whitespace characters.
348+
if (isOnlyInvisibleWhitespace(trimmed)) {
349+
if (tc.isDebugEnabled()) {
350+
Tr.debug(tc, "Ignoring invisible Unicode whitespace at line " + parser.getLocation().getLineNumber());
351+
}
352+
} else {
353+
// At the server level (between top-level elements), there should be NO text content.
354+
// Any non-whitespace text is a malformed element.
355+
Location l = parser.getLocation();
356+
String preview = trimmed.length() > 60 ? trimmed.substring(0, 60) + "..." : trimmed;
357+
logError(ThrowBehavior.SOMETIMES_THROW_EXCEPTION, "error.potential.malformed.element", preview, l.getLineNumber(), docLocation);
358+
}
359+
}
360+
} else if (event == XMLStreamConstants.START_ELEMENT) {
333361
String name = parser.getLocalName();
334362

335363
// Debug: Log element name
@@ -392,6 +420,38 @@ private void parseServer(DepthAwareXMLStreamReader parser, String docLocation, B
392420
}
393421
}
394422

423+
/**
424+
* Checks if a string contains only invisible Unicode whitespace characters.
425+
* These characters are commonly inserted during copy/paste operations from
426+
* web browsers or rich text editors, but they don't affect XML parsing or
427+
* configuration functionality.
428+
*
429+
* @param text The text to check
430+
* @return true if the text contains only invisible whitespace characters, false otherwise
431+
*/
432+
@Trivial
433+
private boolean isOnlyInvisibleWhitespace(String text) {
434+
if (text == null || text.isEmpty()) {
435+
return false;
436+
}
437+
438+
// Check if string contains only invisible Unicode characters:
439+
// U+200B: Zero Width Space
440+
// U+200C: Zero Width Non-Joiner
441+
// U+200D: Zero Width Joiner
442+
// U+FEFF: Zero Width No-Break Space (BOM)
443+
// U+2060: Word Joiner
444+
for (int i = 0; i < text.length(); i++) {
445+
char c = text.charAt(i);
446+
if (c != '\u200B' && c != '\u200C' && c != '\u200D' &&
447+
c != '\uFEFF' && c != '\u2060') {
448+
return false;
449+
}
450+
}
451+
452+
return true;
453+
}
454+
395455
public enum MergeBehavior {
396456
MERGE,
397457
REPLACE,
@@ -925,18 +985,32 @@ private void logError(ThrowBehavior throwBehavior, String msgKey, Object... args
925985
throw new ConfigParserTolerableException();
926986
}
927987
}
928-
988+
989+
/**
990+
* Helper method to get a human-readable name for XML stream event types.
991+
* Used for debug logging.
992+
*
993+
* @param eventType The XMLStreamConstants event type
994+
* @return A string representation of the event type
995+
*/
996+
@Trivial
929997
private String getEventName(int eventType) {
930998
switch (eventType) {
931999
case XMLStreamConstants.START_ELEMENT: return "START_ELEMENT";
9321000
case XMLStreamConstants.END_ELEMENT: return "END_ELEMENT";
933-
case XMLStreamConstants.CHARACTERS: return "CHARACTERS";
1001+
case XMLStreamConstants.CHARACTERS: return "CHARACTERS";
9341002
case XMLStreamConstants.COMMENT: return "COMMENT";
935-
case XMLStreamConstants.START_DOCUMENT: return "START_DOCUMENT";
936-
case XMLStreamConstants.END_DOCUMENT: return "END_DOCUMENT";
9371003
case XMLStreamConstants.PROCESSING_INSTRUCTION: return "PROCESSING_INSTRUCTION";
9381004
case XMLStreamConstants.CDATA: return "CDATA";
9391005
case XMLStreamConstants.SPACE: return "SPACE";
1006+
case XMLStreamConstants.START_DOCUMENT: return "START_DOCUMENT";
1007+
case XMLStreamConstants.END_DOCUMENT: return "END_DOCUMENT";
1008+
case XMLStreamConstants.ENTITY_REFERENCE: return "ENTITY_REFERENCE";
1009+
case XMLStreamConstants.ATTRIBUTE: return "ATTRIBUTE";
1010+
case XMLStreamConstants.DTD: return "DTD";
1011+
case XMLStreamConstants.NAMESPACE: return "NAMESPACE";
1012+
case XMLStreamConstants.NOTATION_DECLARATION: return "NOTATION_DECLARATION";
1013+
case XMLStreamConstants.ENTITY_DECLARATION: return "ENTITY_DECLARATION";
9401014
default: return "UNKNOWN(" + eventType + ")";
9411015
}
9421016
}

0 commit comments

Comments
 (0)