diff --git a/src/PackageUrl.cs b/src/PackageUrl.cs index ae49a2e..324ed2c 100644 --- a/src/PackageUrl.cs +++ b/src/PackageUrl.cs @@ -42,6 +42,11 @@ namespace PackageUrl [Serializable] public sealed class PackageURL { + /// + /// The url encoding of /. + /// + private const string EncodedSlash = "%2F"; + private static readonly Regex s_typePattern = new Regex("^[a-zA-Z][a-zA-Z0-9.+-]+$", RegexOptions.Compiled); /// @@ -135,7 +140,8 @@ public override string ToString() purl.Append('/'); if (Namespace != null) { - purl.Append(WebUtility.UrlEncode(Namespace)); + string encodedNamespace = WebUtility.UrlEncode(Namespace).Replace(EncodedSlash, "/"); + purl.Append(encodedNamespace); purl.Append('/'); } if (Name != null) @@ -238,7 +244,7 @@ private void Parse(string purl) int i; for (i = 1; i < firstPartArray.Length - 2; ++i) { - @namespace += firstPartArray[i] + ','; + @namespace += firstPartArray[i] + '/'; } @namespace += firstPartArray[i]; diff --git a/tests/TestAssets/test-suite-data.json b/tests/TestAssets/test-suite-data.json index 6f97708..25fdf13 100644 --- a/tests/TestAssets/test-suite-data.json +++ b/tests/TestAssets/test-suite-data.json @@ -47,6 +47,18 @@ "subpath": "googleapis/api/annotations", "is_invalid": false }, + { + "description": "valid go purl with version, subpath, and multi-part namespace", + "purl": "pkg:GOLANG/github.com/gorilla/context@234fd47e07d1004f0aed9c#api/", + "canonical_purl": "pkg:golang/github.com/gorilla/context@234fd47e07d1004f0aed9c#api", + "type": "golang", + "namespace": "github.com/gorilla", + "name": "context", + "version": "234fd47e07d1004f0aed9c", + "qualifiers": null, + "subpath": "api", + "is_invalid": false + }, { "description": "bitbucket namespace and name should be lowercased", "purl": "pkg:bitbucket/birKenfeld/pyGments-main@244fd47e07d1014f0aed9c",