|
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