|
28 | 28 | import java.net.URISyntaxException; |
29 | 29 | import java.nio.ByteBuffer; |
30 | 30 | import java.nio.charset.StandardCharsets; |
| 31 | +import java.util.ArrayList; |
31 | 32 | import java.util.Arrays; |
32 | 33 | import java.util.Collections; |
| 34 | +import java.util.List; |
33 | 35 | import java.util.Map; |
34 | 36 | import java.util.Objects; |
35 | 37 | import java.util.Set; |
@@ -443,30 +445,34 @@ private static void validateValue(final String key, final @Nullable String value |
443 | 445 | return validatePath(value.split("/"), true); |
444 | 446 | } |
445 | 447 |
|
446 | | - private static @Nullable String validatePath(final String[] segments, final boolean isSubPath) |
| 448 | + private static @Nullable String validatePath(final String[] segments, final boolean isSubpath) |
447 | 449 | throws MalformedPackageURLException { |
448 | | - if (segments.length == 0) { |
| 450 | + int length = segments.length; |
| 451 | + |
| 452 | + if (length == 0) { |
449 | 453 | return null; |
450 | 454 | } |
451 | | - try { |
452 | | - return Arrays.stream(segments) |
453 | | - .peek(segment -> { |
454 | | - if (isSubPath && ("..".equals(segment) || ".".equals(segment))) { |
455 | | - throw new ValidationException( |
456 | | - "Segments in the subpath may not be a period ('.') or repeated period ('..')"); |
457 | | - } else if (segment.contains("/")) { |
458 | | - throw new ValidationException( |
459 | | - "Segments in the namespace and subpath may not contain a forward slash ('/')"); |
460 | | - } else if (segment.isEmpty()) { |
461 | | - throw new ValidationException("Segments in the namespace and subpath may not be empty"); |
462 | | - } |
463 | | - }) |
464 | | - .collect(Collectors.joining("/")); |
465 | | - } catch (ValidationException e) { |
466 | | - throw new MalformedPackageURLException(e); |
| 455 | + |
| 456 | + List<String> newSegments = new ArrayList<>(length); |
| 457 | + |
| 458 | + for (String segment : segments) { |
| 459 | + if (".".equals(segment) || "..".equals(segment)) { |
| 460 | + if (!isSubpath) { |
| 461 | + throw new MalformedPackageURLException( |
| 462 | + "Segments in the namespace must not be a period ('.') or repeated period ('..'): '" |
| 463 | + + segment + "'"); |
| 464 | + } |
| 465 | + } else if (segment.isEmpty() || segment.contains("/")) { |
| 466 | + throw new MalformedPackageURLException( |
| 467 | + "Segments in the namespace and subpath must not contain a '/' and must not be empty: '" |
| 468 | + + segment + "'"); |
| 469 | + } else { |
| 470 | + newSegments.add(segment); |
| 471 | + } |
467 | 472 | } |
468 | | - } |
469 | 473 |
|
| 474 | + return String.join("/", newSegments); |
| 475 | + } |
470 | 476 | /** |
471 | 477 | * Returns the canonicalized representation of the purl. |
472 | 478 | * |
@@ -876,8 +882,8 @@ private void verifyTypeConstraints(String type, @Nullable String namespace, @Nul |
876 | 882 | } |
877 | 883 | } |
878 | 884 |
|
879 | | - private String[] parsePath(final String path, final boolean isSubpath) { |
880 | | - return Arrays.stream(path.split("/")) |
| 885 | + private String[] parsePath(final String encodedPath, final boolean isSubpath) { |
| 886 | + return Arrays.stream(encodedPath.split("/")) |
881 | 887 | .filter(segment -> !segment.isEmpty() && !(isSubpath && (".".equals(segment) || "..".equals(segment)))) |
882 | 888 | .map(PackageURL::percentDecode) |
883 | 889 | .toArray(String[]::new); |
|
0 commit comments