Skip to content

Commit a2d25c2

Browse files
committed
Better handle empty comps in substring filters
Updated the Filter methods for creating substring filters to better support empty components. In LDAP filters, filters are transmitted using a binary encoding, and substring components may be absent but not empty. However, because developers creating LDAP-enabled applications are more likely to be familiar with the string representations of filters, it is understandable if someone were to try to provide an empty string instead of null to indicate that the component is not needed. The methods for creating substring filters will now interpret empty components as equivalent to being null, causing them to be omitted from the resulting encoded LDAP filter.
1 parent 3dd7837 commit a2d25c2

File tree

3 files changed

+348
-29
lines changed

3 files changed

+348
-29
lines changed

docs/release-notes.html

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,31 @@
66

77
<h2>Release Notes</h2>
88

9+
<h3>Version 6.0.11</h3>
10+
11+
<p>
12+
The following changes were made between the 6.0.10 and 6.0.11 releases:
13+
</p>
14+
15+
<ul>
16+
<li>
17+
Updated the Filter methods for creating substring filters to better support empty
18+
components. In LDAP filters, filters are transmitted using a binary encoding,
19+
and substring components may be absent but not empty. However, because
20+
developers creating LDAP-enabled applications are more likely to be familiar with
21+
the string representations of filters, it is understandable if someone were to
22+
try to provide an empty string instead of null to indicate that the component is
23+
not needed. The methods for creating substring filters will now interpret empty
24+
components as equivalent to being null, causing them to be omitted from the
25+
resulting encoded LDAP filter.
26+
<br><br>
27+
</li>
28+
</ul>
29+
30+
<p></p>
31+
32+
33+
934
<h3>Version 6.0.10</h3>
1035

1136
<p>

src/com/unboundid/ldap/sdk/Filter.java

Lines changed: 100 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -806,9 +806,14 @@ static Filter createEqualityFilter(@NotNull final String attributeName,
806806
* @param attributeName The attribute name for this substring filter. It
807807
* must not be {@code null}.
808808
* @param subInitial The subInitial component for this substring filter.
809+
* It may be {@code null} if there is no subInitial
810+
* component, but it must not be empty.
809811
* @param subAny The set of subAny components for this substring
810-
* filter.
812+
* filter. It may be {@code null} or empty if there
813+
* are no subAny components.
811814
* @param subFinal The subFinal component for this substring filter.
815+
* It may be {@code null} if there is no subFinal
816+
* component, but it must not be empty.
812817
*
813818
* @return The created substring search filter.
814819
*/
@@ -835,9 +840,14 @@ public static Filter substring(@NotNull final String attributeName,
835840
* @param attributeName The attribute name for this substring filter. It
836841
* must not be {@code null}.
837842
* @param subInitial The subInitial component for this substring filter.
843+
* It may be {@code null} if there is no subInitial
844+
* component, but it must not be empty.
838845
* @param subAny The set of subAny components for this substring
839-
* filter.
846+
* filter. It may be {@code null} or empty if there
847+
* are no subAny components.
840848
* @param subFinal The subFinal component for this substring filter.
849+
* It may be {@code null} if there is no subFinal
850+
* component, but it must not be empty.
841851
*
842852
* @return The created substring search filter.
843853
*/
@@ -860,9 +870,14 @@ public static Filter substring(@NotNull final String attributeName,
860870
* @param attributeName The attribute name for this substring filter. It
861871
* must not be {@code null}.
862872
* @param subInitial The subInitial component for this substring filter.
873+
* It may be {@code null} if there is no subInitial
874+
* component, but it must not be empty.
863875
* @param subAny The set of subAny components for this substring
864-
* filter.
876+
* filter. It may be {@code null} or empty if there
877+
* are no subAny components.
865878
* @param subFinal The subFinal component for this substring filter.
879+
* It may be {@code null} if there is no subFinal
880+
* component, but it must not be empty.
866881
*
867882
* @return The created substring search filter.
868883
*/
@@ -874,12 +889,16 @@ public static Filter createSubstringFilter(
874889
@Nullable final String subFinal)
875890
{
876891
Validator.ensureNotNull(attributeName);
877-
Validator.ensureTrue((subInitial != null) ||
878-
((subAny != null) && (subAny.length > 0)) ||
879-
(subFinal != null));
892+
Validator.ensureTrue(
893+
(((subInitial != null) && (subInitial.length() > 0)) ||
894+
((subAny != null) && (subAny.length > 0) &&
895+
(subAny[0].length() > 0)) ||
896+
((subFinal != null) && (subFinal.length() > 0))),
897+
"At least one substring filter component must be non-null and " +
898+
"non-empty");
880899

881900
final ASN1OctetString subInitialOS;
882-
if (subInitial == null)
901+
if ((subInitial == null) || subInitial.isEmpty())
883902
{
884903
subInitialOS = null;
885904
}
@@ -895,15 +914,34 @@ public static Filter createSubstringFilter(
895914
}
896915
else
897916
{
898-
subAnyArray = new ASN1OctetString[subAny.length];
899-
for (int i=0; i < subAny.length; i++)
917+
if (subAny.length == 1)
918+
{
919+
if (subAny[0].length() == 0)
920+
{
921+
subAnyArray = NO_SUB_ANY;
922+
}
923+
else
924+
{
925+
subAnyArray = new ASN1OctetString[]
926+
{
927+
new ASN1OctetString(subAny[0])
928+
};
929+
}
930+
}
931+
else
900932
{
901-
subAnyArray[i] = new ASN1OctetString(subAny[i]);
933+
subAnyArray = new ASN1OctetString[subAny.length];
934+
for (int i=0; i < subAny.length; i++)
935+
{
936+
Validator.ensureFalse(subAny[i].isEmpty(),
937+
"Individual substring filter components must not be empty");
938+
subAnyArray[i] = new ASN1OctetString(subAny[i]);
939+
}
902940
}
903941
}
904942

905943
final ASN1OctetString subFinalOS;
906-
if (subFinal == null)
944+
if ((subFinal == null) || subFinal.isEmpty())
907945
{
908946
subFinalOS = null;
909947
}
@@ -927,9 +965,14 @@ public static Filter createSubstringFilter(
927965
* @param attributeName The attribute name for this substring filter. It
928966
* must not be {@code null}.
929967
* @param subInitial The subInitial component for this substring filter.
968+
* It may be {@code null} if there is no subInitial
969+
* component, but it must not be empty.
930970
* @param subAny The set of subAny components for this substring
931-
* filter.
971+
* filter. It may be {@code null} or empty if there
972+
* are no subAny components.
932973
* @param subFinal The subFinal component for this substring filter.
974+
* It may be {@code null} if there is no subFinal
975+
* component, but it must not be empty.
933976
*
934977
* @return The created substring search filter.
935978
*/
@@ -941,12 +984,16 @@ public static Filter createSubstringFilter(
941984
@Nullable final byte[] subFinal)
942985
{
943986
Validator.ensureNotNull(attributeName);
944-
Validator.ensureTrue((subInitial != null) ||
945-
((subAny != null) && (subAny.length > 0)) ||
946-
(subFinal != null));
987+
Validator.ensureTrue(
988+
(((subInitial != null) && (subInitial.length > 0)) ||
989+
((subAny != null) && (subAny.length > 0) &&
990+
(subAny[0].length > 0)) ||
991+
((subFinal != null) && (subFinal.length > 0))),
992+
"At least one substring filter component must be non-null and " +
993+
"non-empty");
947994

948995
final ASN1OctetString subInitialOS;
949-
if (subInitial == null)
996+
if ((subInitial == null) || (subInitial.length == 0))
950997
{
951998
subInitialOS = null;
952999
}
@@ -962,15 +1009,34 @@ public static Filter createSubstringFilter(
9621009
}
9631010
else
9641011
{
965-
subAnyArray = new ASN1OctetString[subAny.length];
966-
for (int i=0; i < subAny.length; i++)
1012+
if (subAny.length == 1)
9671013
{
968-
subAnyArray[i] = new ASN1OctetString(subAny[i]);
1014+
if (subAny[0].length == 0)
1015+
{
1016+
subAnyArray = NO_SUB_ANY;
1017+
}
1018+
else
1019+
{
1020+
subAnyArray = new ASN1OctetString[]
1021+
{
1022+
new ASN1OctetString(subAny[0])
1023+
};
1024+
}
1025+
}
1026+
else
1027+
{
1028+
subAnyArray = new ASN1OctetString[subAny.length];
1029+
for (int i=0; i < subAny.length; i++)
1030+
{
1031+
Validator.ensureTrue((subAny[i].length > 0),
1032+
"Individual substring filter components must not be empty");
1033+
subAnyArray[i] = new ASN1OctetString(subAny[i]);
1034+
}
9691035
}
9701036
}
9711037

9721038
final ASN1OctetString subFinalOS;
973-
if (subFinal == null)
1039+
if ((subFinal == null) || (subFinal.length == 0))
9741040
{
9751041
subFinalOS = null;
9761042
}
@@ -994,9 +1060,14 @@ public static Filter createSubstringFilter(
9941060
* @param attributeName The attribute name for this substring filter. It
9951061
* must not be {@code null}.
9961062
* @param subInitial The subInitial component for this substring filter.
1063+
* It may be {@code null} if there is no subInitial
1064+
* component, but it must not be empty.
9971065
* @param subAny The set of subAny components for this substring
998-
* filter.
1066+
* filter. It may be {@code null} or empty if there
1067+
* are no subAny components.
9991068
* @param subFinal The subFinal component for this substring filter.
1069+
* It may be {@code null} if there is no subFinal
1070+
* component, but it must not be empty.
10001071
*
10011072
* @return The created substring search filter.
10021073
*/
@@ -1038,7 +1109,7 @@ static Filter createSubstringFilter(@NotNull final String attributeName,
10381109
* @param attributeName The attribute name for this substring filter. It
10391110
* must not be {@code null}.
10401111
* @param subInitial The subInitial component for this substring filter.
1041-
* It must not be {@code null}.
1112+
* It must not be {@code null} or empty.
10421113
*
10431114
* @return The created substring search filter.
10441115
*/
@@ -1062,7 +1133,7 @@ public static Filter subInitial(@NotNull final String attributeName,
10621133
* @param attributeName The attribute name for this substring filter. It
10631134
* must not be {@code null}.
10641135
* @param subInitial The subInitial component for this substring filter.
1065-
* It must not be {@code null}.
1136+
* It must not be {@code null} or empty.
10661137
*
10671138
* @return The created substring search filter.
10681139
*/
@@ -1082,7 +1153,7 @@ public static Filter subInitial(@NotNull final String attributeName,
10821153
* @param attributeName The attribute name for this substring filter. It
10831154
* must not be {@code null}.
10841155
* @param subInitial The subInitial component for this substring filter.
1085-
* It must not be {@code null}.
1156+
* It must not be {@code null} or empty.
10861157
*
10871158
* @return The created substring search filter.
10881159
*/
@@ -1103,7 +1174,7 @@ public static Filter createSubInitialFilter(
11031174
* @param attributeName The attribute name for this substring filter. It
11041175
* must not be {@code null}.
11051176
* @param subInitial The subInitial component for this substring filter.
1106-
* It must not be {@code null}.
1177+
* It must not be {@code null} or empty.
11071178
*
11081179
* @return The created substring search filter.
11091180
*/
@@ -1216,7 +1287,7 @@ public static Filter createSubAnyFilter(@NotNull final String attributeName,
12161287
* @param attributeName The attribute name for this substring filter. It
12171288
* must not be {@code null}.
12181289
* @param subFinal The subFinal component for this substring filter.
1219-
* It must not be {@code null}.
1290+
* It must not be {@code null} or empty.
12201291
*
12211292
* @return The created substring search filter.
12221293
*/
@@ -1240,7 +1311,7 @@ public static Filter subFinal(@NotNull final String attributeName,
12401311
* @param attributeName The attribute name for this substring filter. It
12411312
* must not be {@code null}.
12421313
* @param subFinal The subFinal component for this substring filter.
1243-
* It must not be {@code null}.
1314+
* It must not be {@code null} or empty.
12441315
*
12451316
* @return The created substring search filter.
12461317
*/
@@ -1260,7 +1331,7 @@ public static Filter subFinal(@NotNull final String attributeName,
12601331
* @param attributeName The attribute name for this substring filter. It
12611332
* must not be {@code null}.
12621333
* @param subFinal The subFinal component for this substring filter.
1263-
* It must not be {@code null}.
1334+
* It must not be {@code null} or empty.
12641335
*
12651336
* @return The created substring search filter.
12661337
*/
@@ -1280,7 +1351,7 @@ public static Filter createSubFinalFilter(@NotNull final String attributeName,
12801351
* @param attributeName The attribute name for this substring filter. It
12811352
* must not be {@code null}.
12821353
* @param subFinal The subFinal component for this substring filter.
1283-
* It must not be {@code null}.
1354+
* It must not be {@code null} or empty.
12841355
*
12851356
* @return The created substring search filter.
12861357
*/

0 commit comments

Comments
 (0)