Skip to content

Commit 050ad9f

Browse files
committed
Silently drop empty and dot segments for subpath
This change makes the two test pass that were introduced in package-url/purl-spec#368. See also package-url/purl-spec#404.
1 parent 681b0aa commit 050ad9f

File tree

2 files changed

+28
-19
lines changed

2 files changed

+28
-19
lines changed

src/main/java/com/github/packageurl/PackageURL.java

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
* @since 1.0.0
5252
*/
5353
public final class PackageURL implements Serializable {
54-
5554
private static final long serialVersionUID = 3243226021636427586L;
5655

5756
/**
@@ -413,22 +412,31 @@ private String validateSubpath(final String value) throws MalformedPackageURLExc
413412
return validatePath(value.split("/"), true);
414413
}
415414

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 {
417420
if (segments == null || segments.length == 0) {
418421
return null;
419422
}
423+
420424
try {
421425
return Arrays.stream(segments)
422426
.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+
}
429435
}
430436
return segment;
431-
}).collect(Collectors.joining("/"));
437+
})
438+
.filter(segment1 -> shouldKeepSegment(segment1, isSubpath))
439+
.collect(Collectors.joining("/"));
432440
} catch (ValidationException e) {
433441
throw new MalformedPackageURLException(e);
434442
}
@@ -591,7 +599,7 @@ private static String toLowerCase(String s) {
591599
* @param input the value String to decode
592600
* @return a decoded String
593601
*/
594-
private String percentDecode(final String input) {
602+
private static String percentDecode(final String input) {
595603
if (input == null) {
596604
return null;
597605
}
@@ -761,10 +769,13 @@ private Map<String, String> parseQualifiers(final String encodedString) throws M
761769
}
762770
}
763771

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))
768779
.toArray(String[]::new);
769780
}
770781

src/test/java/com/github/packageurl/PackageURLTest.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -232,11 +232,9 @@ public void testConstructorWithInvalidNumberType() throws MalformedPackageURLExc
232232
}
233233

234234
@Test
235-
public void testConstructorWithInvalidSubpath() throws MalformedPackageURLException {
236-
exception.expect(MalformedPackageURLException.class);
237-
238-
PackageURL purl = new PackageURL("pkg:GOLANG/google.golang.org/genproto@abcdedf#invalid/%2F/subpath");
239-
Assert.fail("constructor with `invalid/%2F/subpath` should have thrown an error and this line should not be reached");
235+
public void testConstructorWithValidSubpathContainingSlashIsDropped() throws MalformedPackageURLException {
236+
PackageURL purl = new PackageURL("pkg:GOLANG/google.golang.org/genproto@abcdedf#valid/%2F/subpath");
237+
Assert.assertEquals("valid/subpath", purl.getSubpath());
240238
}
241239

242240

0 commit comments

Comments
 (0)