|
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