Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions purl/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ const PATH: &AsciiSet = &QUERY.add(b'?').add(b'`').add(b'{').add(b'}');

// https://github.com/package-url/purl-spec/blob/master/PURL-SPECIFICATION.rst#how-to-build-purl-string-from-its-components
// We mostly use the standard URL rules, but the PURL spec says '@' '?' '#' must
// be escaped except when used as a separator.
const PURL_PATH: &AsciiSet = &PATH.add(b'@').add(b'?').add(b'#');
// be escaped except when used as a separator, and we do all the encoding in one
// pass so we need to include '%'.
const PURL_PATH: &AsciiSet = &PATH.add(b'@').add(b'?').add(b'#').add(b'%');
const PURL_PATH_SEGMENT: &AsciiSet = &PURL_PATH.add(b'/');
// For compatibility with PURL implementations that treat qualifiers as
// form-urlencoded, escape '+' as well.
const PURL_QUERY: &AsciiSet = &QUERY.add(b'@').add(b'?').add(b'#').add(b'+');
const PURL_FRAGMENT: &AsciiSet = &FRAGMENT.add(b'@').add(b'?').add(b'#');
const PURL_QUERY: &AsciiSet = &QUERY.add(b'@').add(b'?').add(b'#').add(b'+').add(b'%');
const PURL_FRAGMENT: &AsciiSet = &FRAGMENT.add(b'@').add(b'?').add(b'#').add(b'%');

impl<T> fmt::Display for GenericPurl<T>
where
Expand Down
36 changes: 36 additions & 0 deletions purl_test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1260,3 +1260,39 @@ fn plus_signs_and_spaces() {
"Incorrect string representation"
);
}
#[test]
/// unsupported: percent signs are properly encoded and decoded
fn unsupported_percent_signs_are_properly_encoded_and_decoded() {
assert!(
matches!(Purl::from_str("pkg:generic/100%25/100%25@100%25?repository_url=https://example.com/100%2525/#100%25"),
Err(PackageError::UnsupportedType)), "Type {} is not supported", "generic"
);
let parsed = match GenericPurl::<String>::from_str(
"pkg:generic/100%25/100%25@100%25?repository_url=https://example.com/100%2525/#100%25",
) {
Ok(purl) => purl,
Err(error) => {
panic!(
"Failed to parse valid purl {:?}: {}",
"pkg:generic/100%25/100%25@100%25?repository_url=https://example.com/100%2525/#100%25",
error
)
},
};
assert_eq!("generic", parsed.package_type(), "Incorrect package type");
assert_eq!(Some("100%"), parsed.namespace(), "Incorrect namespace");
assert_eq!("100%", parsed.name(), "Incorrect name");
assert_eq!(Some("100%"), parsed.version(), "Incorrect version");
assert_eq!(Some("100%"), parsed.subpath(), "Incorrect subpath");
let expected_qualifiers: HashMap<&str, &str> =
[("repository_url", "https://example.com/100%25/")].into_iter().collect();
assert_eq!(
expected_qualifiers,
parsed.qualifiers().iter().map(|(k, v)| (k.as_str(), v)).collect::<HashMap<&str, &str>>()
);
assert_eq!(
"pkg:generic/100%25/100%25@100%25?repository_url=https://example.com/100%2525/#100%25",
&parsed.to_string(),
"Incorrect string representation"
);
}
14 changes: 14 additions & 0 deletions xtask/src/generate_tests/phylum-test-suite-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,5 +120,19 @@
},
"subpath": null,
"is_invalid": false
},
{
"description": "percent signs are properly encoded and decoded",
"purl": "pkg:generic/100%25/100%25@100%25?repository_url=https://example.com/100%2525/#100%25",
"canonical_purl": "pkg:generic/100%25/100%25@100%25?repository_url=https://example.com/100%2525/#100%25",
"type": "generic",
"namespace": "100%",
"name": "100%",
"version": "100%",
"qualifiers": {
"repository_url": "https://example.com/100%25/"
},
"subpath": "100%",
"is_invalid": false
}
]