|
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.TreeMap; |
@@ -421,26 +423,29 @@ private static void validateValue(final String key, final @Nullable String value |
421 | 423 | return validatePath(value.split("/"), true); |
422 | 424 | } |
423 | 425 |
|
424 | | - private static @Nullable String validatePath(final String[] segments, final boolean isSubPath) throws MalformedPackageURLException { |
425 | | - if (segments.length == 0) { |
| 426 | + private static @Nullable String validatePath(final String[] segments, final boolean isSubpath) throws MalformedPackageURLException { |
| 427 | + int length = segments.length; |
| 428 | + |
| 429 | + if (length == 0) { |
426 | 430 | return null; |
427 | 431 | } |
428 | | - try { |
429 | | - return Arrays.stream(segments) |
430 | | - .peek(segment -> { |
431 | | - if (isSubPath && ("..".equals(segment) || ".".equals(segment))) { |
432 | | - throw new ValidationException("Segments in the subpath may not be a period ('.') or repeated period ('..')"); |
433 | | - } else if (segment.contains("/")) { |
434 | | - throw new ValidationException("Segments in the namespace and subpath may not contain a forward slash ('/')"); |
435 | | - } else if (segment.isEmpty()) { |
436 | | - throw new ValidationException("Segments in the namespace and subpath may not be empty"); |
437 | | - } |
438 | | - }).collect(Collectors.joining("/")); |
439 | | - } catch (ValidationException e) { |
440 | | - throw new MalformedPackageURLException(e); |
| 432 | + |
| 433 | + List<String> newSegments = new ArrayList<>(length); |
| 434 | + |
| 435 | + for (String segment : segments) { |
| 436 | + if (".".equals(segment) || "..".equals(segment)) { |
| 437 | + if (!isSubpath) { |
| 438 | + throw new MalformedPackageURLException("Segments in the namespace must not be a period ('.') or repeated period ('..'): '" + segment + "'"); |
| 439 | + } |
| 440 | + } else if (segment.isEmpty() || segment.contains("/")) { |
| 441 | + throw new MalformedPackageURLException("Segments in the namespace and subpath must not contain a '/' and must not be empty: '" + segment + "'"); |
| 442 | + } else { |
| 443 | + newSegments.add(segment); |
| 444 | + } |
441 | 445 | } |
442 | | - } |
443 | 446 |
|
| 447 | + return String.join("/", newSegments); |
| 448 | + } |
444 | 449 | /** |
445 | 450 | * Returns the canonicalized representation of the purl. |
446 | 451 | * |
@@ -828,8 +833,8 @@ private void verifyTypeConstraints(String type, @Nullable String namespace, @Nul |
828 | 833 | } |
829 | 834 | } |
830 | 835 |
|
831 | | - private String[] parsePath(final String path, final boolean isSubpath) { |
832 | | - return Arrays.stream(path.split("/")) |
| 836 | + private String[] parsePath(final String encodedPath, final boolean isSubpath) { |
| 837 | + return Arrays.stream(encodedPath.split("/")) |
833 | 838 | .filter(segment -> !segment.isEmpty() && !(isSubpath && (".".equals(segment) || "..".equals(segment)))) |
834 | 839 | .map(PackageURL::percentDecode) |
835 | 840 | .toArray(String[]::new); |
|
0 commit comments