|
51 | 51 | * @since 1.0.0 |
52 | 52 | */ |
53 | 53 | public final class PackageURL implements Serializable { |
54 | | - |
55 | 54 | private static final long serialVersionUID = 3243226021636427586L; |
56 | 55 |
|
57 | 56 | /** |
@@ -413,22 +412,31 @@ private String validateSubpath(final String value) throws MalformedPackageURLExc |
413 | 412 | return validatePath(value.split("/"), true); |
414 | 413 | } |
415 | 414 |
|
416 | | - private String validatePath(final String[] segments, final boolean isSubpath) throws MalformedPackageURLException { |
| 415 | + private static boolean shouldKeepSegment(String segment, boolean isSubpath) { |
| 416 | + return (!isSubpath || (!segment.isEmpty() && !".".equals(segment) && !"..".equals(segment))); |
| 417 | + } |
| 418 | + |
| 419 | + private static String validatePath(final String[] segments, final boolean isSubpath) throws MalformedPackageURLException { |
417 | 420 | if (segments == null || segments.length == 0) { |
418 | 421 | return null; |
419 | 422 | } |
| 423 | + |
420 | 424 | try { |
421 | 425 | return Arrays.stream(segments) |
422 | 426 | .map(segment -> { |
423 | | - if (isSubpath && ("..".equals(segment) || ".".equals(segment))) { |
424 | | - throw new ValidationException("Segments in the subpath may not be a period ('.') or repeated period ('..')"); |
425 | | - } else if (segment.contains("/")) { |
426 | | - throw new ValidationException("Segments in the namespace and subpath may not contain a forward slash ('/')"); |
427 | | - } else if (segment.isEmpty()) { |
428 | | - throw new ValidationException("Segments in the namespace and subpath may not be empty"); |
| 427 | + if (!isSubpath) { |
| 428 | + if ("..".equals(segment) || ".".equals(segment)) { |
| 429 | + throw new ValidationException("Segments in the namespace may not be a period ('.') or repeated period ('..')"); |
| 430 | + } else if (segment.contains("/")) { |
| 431 | + throw new ValidationException("Segments in the namespace and subpath may not contain a forward slash ('/')"); |
| 432 | + } else if (segment.isEmpty()) { |
| 433 | + throw new ValidationException("Segments in the namespace and subpath may not be empty"); |
| 434 | + } |
429 | 435 | } |
430 | 436 | return segment; |
431 | | - }).collect(Collectors.joining("/")); |
| 437 | + }) |
| 438 | + .filter(segment1 -> shouldKeepSegment(segment1, isSubpath)) |
| 439 | + .collect(Collectors.joining("/")); |
432 | 440 | } catch (ValidationException e) { |
433 | 441 | throw new MalformedPackageURLException(e); |
434 | 442 | } |
@@ -591,7 +599,7 @@ private static String toLowerCase(String s) { |
591 | 599 | * @param input the value String to decode |
592 | 600 | * @return a decoded String |
593 | 601 | */ |
594 | | - private String percentDecode(final String input) { |
| 602 | + private static String percentDecode(final String input) { |
595 | 603 | if (input == null) { |
596 | 604 | return null; |
597 | 605 | } |
@@ -761,10 +769,13 @@ private Map<String, String> parseQualifiers(final String encodedString) throws M |
761 | 769 | } |
762 | 770 | } |
763 | 771 |
|
764 | | - private String[] parsePath(final String path, final boolean isSubpath) { |
765 | | - return Arrays.stream(path.split("/")) |
766 | | - .filter(segment -> !segment.isEmpty() && !(isSubpath && (".".equals(segment) || "..".equals(segment)))) |
767 | | - .map(this::percentDecode) |
| 772 | + private static String[] parsePath(final String value, final boolean isSubpath) { |
| 773 | + if (value == null || value.isEmpty()) { |
| 774 | + return null; |
| 775 | + } |
| 776 | + |
| 777 | + return Arrays.stream(percentDecode(value).split("/")) |
| 778 | + .filter(segment -> shouldKeepSegment(segment, isSubpath)) |
768 | 779 | .toArray(String[]::new); |
769 | 780 | } |
770 | 781 |
|
|
0 commit comments