From 3f4deb91789189521d577457bd6da27de8fd75b1 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Wed, 07 Oct 2026 08:31:10 +0000
Subject: [PATCH] [#1153] Parse the whole DN string, and build or split DN strings through DN instead of string operations (#1171)
---
opendj-server-legacy/src/main/java/org/opends/server/replication/common/MultiDomainServerState.java | 58 +++++++++++++++++++++++++++++++++++++++++++---------------
1 files changed, 43 insertions(+), 15 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/common/MultiDomainServerState.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/common/MultiDomainServerState.java
index 2500547..a2275b8 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/common/MultiDomainServerState.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/common/MultiDomainServerState.java
@@ -13,11 +13,13 @@
*
* Copyright 2006-2009 Sun Microsystems, Inc.
* Portions Copyright 2011-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
*/
package org.opends.server.replication.common;
import static org.opends.messages.ReplicationMessages.*;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
@@ -395,23 +397,18 @@
try
{
// Split the provided multiDomainServerState into domains
- String[] domains = multiDomainServerState.split(";");
- for (String domain : domains)
+ for (String domain : splitDomains(multiDomainServerState))
{
// For each domain, split the CSNs by server
// and build a server state (SHOULD BE OPTIMIZED)
final ServerState serverStateByDomain = new ServerState();
- final String[] fields = domain.split(":");
- if (fields.length == 0)
+ // The base DN may contain ':' (o=urn:x), but a CSN never does: the state starts after the last one.
+ final int colonPos = domain.lastIndexOf(':');
+ final String domainBaseDN = colonPos >= 0 ? domain.substring(0, colonPos) : domain;
+ if (colonPos >= 0 && colonPos + 1 < domain.length())
{
- throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
- ERR_INVALID_COOKIE_SYNTAX.get(multiDomainServerState));
- }
- final String domainBaseDN = fields[0];
- if (fields.length > 1)
- {
- final String serverStateStr = fields[1];
+ final String serverStateStr = domain.substring(colonPos + 1);
for (String csnStr : serverStateStr.split(" "))
{
final CSN csn = new CSN(csnStr);
@@ -421,10 +418,6 @@
startStates.put(DN.valueOf(domainBaseDN), serverStateByDomain);
}
}
- catch (DirectoryException de)
- {
- throw de;
- }
catch (Exception e)
{
throw new DirectoryException(
@@ -435,4 +428,39 @@
}
return startStates;
}
+
+ /**
+ * Splits the provided cookie at each ';' that ends a domain. {@link DN#toString()} escapes a ';' of the base DN
+ * as "\;", so a ';' preceded by an unescaped backslash belongs to the base DN. As {@link String#split(String)}
+ * did, empty trailing domains are dropped.
+ */
+ private static List<String> splitDomains(String multiDomainServerState)
+ {
+ final List<String> domains = new ArrayList<>();
+ int start = 0;
+ boolean escaped = false;
+ for (int i = 0; i < multiDomainServerState.length(); i++)
+ {
+ final char c = multiDomainServerState.charAt(i);
+ if (escaped)
+ {
+ escaped = false;
+ }
+ else if (c == '\\')
+ {
+ escaped = true;
+ }
+ else if (c == ';')
+ {
+ domains.add(multiDomainServerState.substring(start, i));
+ start = i + 1;
+ }
+ }
+ domains.add(multiDomainServerState.substring(start));
+ while (!domains.isEmpty() && domains.get(domains.size() - 1).isEmpty())
+ {
+ domains.remove(domains.size() - 1);
+ }
+ return domains;
+ }
}
--
Gitblit v1.10.0