|
31 | 31 | import java.util.Map; |
32 | 32 | import java.util.Objects; |
33 | 33 | import java.util.TreeMap; |
34 | | -import java.util.regex.Pattern; |
35 | 34 | import java.util.stream.Collectors; |
36 | 35 |
|
37 | 36 | /** |
|
51 | 50 | * @since 1.0.0 |
52 | 51 | */ |
53 | 52 | public final class PackageURL implements Serializable { |
54 | | - |
55 | 53 | private static final long serialVersionUID = 3243226021636427586L; |
56 | | - private static final Pattern PATH_SPLITTER = Pattern.compile("/"); |
57 | 54 |
|
58 | 55 | /** |
59 | 56 | * Constructs a new PackageURL object by parsing the specified string. |
@@ -347,22 +344,31 @@ private String validatePath(final String value, final boolean isSubpath) throws |
347 | 344 | return validatePath(value.split("/"), isSubpath); |
348 | 345 | } |
349 | 346 |
|
350 | | - private String validatePath(final String[] segments, final boolean isSubpath) throws MalformedPackageURLException { |
| 347 | + private static boolean isValidSegment(String segment, boolean isSubpath) { |
| 348 | + return (!isSubpath || (!segment.isEmpty() && !".".equals(segment) && !"..".equals(segment))); |
| 349 | + } |
| 350 | + |
| 351 | + private static String validatePath(final String[] segments, final boolean isSubpath) throws MalformedPackageURLException { |
351 | 352 | if (segments == null || segments.length == 0) { |
352 | 353 | return null; |
353 | 354 | } |
| 355 | + |
354 | 356 | try { |
355 | 357 | return Arrays.stream(segments) |
356 | 358 | .map(segment -> { |
357 | | - if (isSubpath && ("..".equals(segment) || ".".equals(segment))) { |
358 | | - throw new ValidationException("Segments in the subpath may not be a period ('.') or repeated period ('..')"); |
359 | | - } else if (segment.contains("/")) { |
360 | | - throw new ValidationException("Segments in the namespace and subpath may not contain a forward slash ('/')"); |
361 | | - } else if (segment.isEmpty()) { |
362 | | - throw new ValidationException("Segments in the namespace and subpath may not be empty"); |
| 359 | + if (!isSubpath) { |
| 360 | + if ("..".equals(segment) || ".".equals(segment)) { |
| 361 | + throw new ValidationException("Segments in the namespace may not be a period ('.') or repeated period ('..')"); |
| 362 | + } else if (segment.contains("/")) { |
| 363 | + throw new ValidationException("Segments in the namespace and subpath may not contain a forward slash ('/')"); |
| 364 | + } else if (segment.isEmpty()) { |
| 365 | + throw new ValidationException("Segments in the namespace and subpath may not be empty"); |
| 366 | + } |
363 | 367 | } |
364 | 368 | return segment; |
365 | | - }).collect(Collectors.joining("/")); |
| 369 | + }) |
| 370 | + .filter(segment1 -> isValidSegment(segment1, isSubpath)) |
| 371 | + .collect(Collectors.joining("/")); |
366 | 372 | } catch (ValidationException e) { |
367 | 373 | throw new MalformedPackageURLException(e); |
368 | 374 | } |
@@ -478,7 +484,7 @@ private static boolean isDigit(int c) { |
478 | 484 | * @param input the value String to decode |
479 | 485 | * @return a decoded String |
480 | 486 | */ |
481 | | - private String percentDecode(final String input) { |
| 487 | + private static String percentDecode(final String input) { |
482 | 488 | if (input == null) { |
483 | 489 | return null; |
484 | 490 | } |
@@ -629,14 +635,13 @@ private Map<String, String> parseQualifiers(final String encodedString) throws M |
629 | 635 | } |
630 | 636 | } |
631 | 637 |
|
632 | | - @SuppressWarnings("StringSplitter")//reason: surprising behavior is okay in this case |
633 | | - private String[] parsePath(final String value, final boolean isSubpath) throws MalformedPackageURLException { |
| 638 | + private static String[] parsePath(final String value, final boolean isSubpath) { |
634 | 639 | if (value == null || value.isEmpty()) { |
635 | 640 | return null; |
636 | 641 | } |
637 | | - return PATH_SPLITTER.splitAsStream(value) |
638 | | - .filter(segment -> !segment.isEmpty() && !(isSubpath && (".".equals(segment) || "..".equals(segment)))) |
639 | | - .map(segment -> percentDecode(segment)) |
| 642 | + |
| 643 | + return Arrays.stream(percentDecode(value).split("/")) |
| 644 | + .filter(segment ->isValidSegment(segment, isSubpath)) |
640 | 645 | .toArray(String[]::new); |
641 | 646 | } |
642 | 647 |
|
|
0 commit comments