Skip to content

Commit 3d8f707

Browse files
authored
Merge pull request #88 from NuGet/dev
Merge branch 'dev' into master
2 parents 03597a6 + 55f68e9 commit 3d8f707

2 files changed

Lines changed: 99 additions & 6 deletions

File tree

src/NuGet.Server.Core/Infrastructure/JsonNetPackagesSerializer.cs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System;
45
using System.Collections.Generic;
56
using System.IO;
67
using System.Linq;
@@ -18,7 +19,8 @@ public class JsonNetPackagesSerializer
1819
private readonly JsonSerializer _serializer = new JsonSerializer
1920
{
2021
Formatting = Formatting.None,
21-
NullValueHandling = NullValueHandling.Ignore
22+
NullValueHandling = NullValueHandling.Ignore,
23+
Converters = { new AbsoluteUriConverter() },
2224
};
2325

2426
public void Serialize(IEnumerable<ServerPackage> packages, Stream stream)
@@ -51,5 +53,54 @@ public IEnumerable<ServerPackage> Deserialize(Stream stream)
5153
return packages.Packages;
5254
}
5355
}
56+
57+
/// <summary>
58+
/// This is necessary because Newtonsoft.Json creates <see cref="Uri"/> instances with
59+
/// <see cref="UriKind.RelativeOrAbsolute"/> which treats UNC paths as relative. NuGet.Core uses
60+
/// <see cref="UriKind.Absolute"/> which treats UNC paths as absolute. For more details, see:
61+
/// https://github.com/JamesNK/Newtonsoft.Json/issues/2128
62+
/// </summary>
63+
private class AbsoluteUriConverter : JsonConverter
64+
{
65+
public override bool CanConvert(Type objectType)
66+
{
67+
return objectType == typeof(Uri);
68+
}
69+
70+
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
71+
{
72+
if (reader.TokenType == JsonToken.Null)
73+
{
74+
return null;
75+
}
76+
else if (reader.TokenType == JsonToken.String)
77+
{
78+
return new Uri((string)reader.Value, UriKind.Absolute);
79+
}
80+
81+
throw new JsonSerializationException("The JSON value must be a string.");
82+
}
83+
84+
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
85+
{
86+
if (value == null)
87+
{
88+
writer.WriteNull();
89+
return;
90+
}
91+
92+
if (!(value is Uri uriValue))
93+
{
94+
throw new JsonSerializationException("The value must be a URI.");
95+
}
96+
97+
if (!uriValue.IsAbsoluteUri)
98+
{
99+
throw new JsonSerializationException("The URI value must be an absolute Uri. Relative URI instances are not allowed.");
100+
}
101+
102+
writer.WriteValue(uriValue.OriginalString);
103+
}
104+
}
54105
}
55106
}

test/NuGet.Server.Core.Tests/JsonNetPackagesSerializerTests.cs

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,37 @@ namespace NuGet.Server.Core.Tests
1414
{
1515
public class JsonNetPackagesSerializerTests
1616
{
17+
[Fact]
18+
public void RoundTripsUncPaths()
19+
{
20+
var originalPackages = GenerateServerPackages(1);
21+
var originalPackage = originalPackages.Single();
22+
originalPackage.IconUrl = new Uri("//testunc/test/a", UriKind.Absolute);
23+
originalPackage.LicenseUrl = new Uri("//testunc/test/b", UriKind.Absolute);
24+
originalPackage.ProjectUrl = new Uri("//testunc/test/c", UriKind.Absolute);
25+
originalPackage.ReportAbuseUrl = new Uri("//testunc/test/d", UriKind.Absolute);
26+
var serializer = new JsonNetPackagesSerializer();
27+
28+
// Act
29+
var deserializedPackages = new List<ServerPackage>();
30+
using (var memoryStream = new MemoryStream())
31+
{
32+
serializer.Serialize(originalPackages, memoryStream);
33+
34+
memoryStream.Position = 0;
35+
36+
deserializedPackages.AddRange(serializer.Deserialize(memoryStream));
37+
}
38+
39+
// Assert
40+
AssertPackagesAreEqual(originalPackages, deserializedPackages);
41+
var deserializedPackage = deserializedPackages.Single();
42+
Assert.True(deserializedPackage.IconUrl.IsAbsoluteUri, "The icon URL should still be absolute.");
43+
Assert.True(deserializedPackage.LicenseUrl.IsAbsoluteUri, "The license URL should still be absolute.");
44+
Assert.True(deserializedPackage.ProjectUrl.IsAbsoluteUri, "The project URL should still be absolute.");
45+
Assert.True(deserializedPackage.ReportAbuseUrl.IsAbsoluteUri, "The report abuse URL should still be absolute.");
46+
}
47+
1748
[Fact]
1849
public void TestSerializationRoundTrip()
1950
{
@@ -33,14 +64,25 @@ public void TestSerializationRoundTrip()
3364
}
3465

3566
// Assert
67+
AssertPackagesAreEqual(originalPackages, deserializedPackages);
68+
}
69+
70+
private static void AssertPackagesAreEqual(List<ServerPackage> originalPackages, List<ServerPackage> deserializedPackages)
71+
{
3672
Assert.Equal(originalPackages.Count, deserializedPackages.Count);
3773
for (var i = 0; i < originalPackages.Count; i++)
3874
{
39-
Assert.True(PublicPropertiesEqual(originalPackages[i], deserializedPackages[i], "DependencySets", "FrameworkAssemblies", "PackageAssemblyReferences", "AssemblyReferences"));
75+
AssertPublicPropertiesEqual(
76+
originalPackages[i],
77+
deserializedPackages[i],
78+
"DependencySets",
79+
"FrameworkAssemblies",
80+
"PackageAssemblyReferences",
81+
"AssemblyReferences");
4082
}
4183
}
4284

43-
private static bool PublicPropertiesEqual<T>(T a, T b, params string[] ignoreProperties) where T : class
85+
private static void AssertPublicPropertiesEqual<T>(T a, T b, params string[] ignoreProperties) where T : class
4486
{
4587
if (a != null && b != null)
4688
{
@@ -55,15 +97,15 @@ private static bool PublicPropertiesEqual<T>(T a, T b, params string[] ignorePro
5597

5698
if (selfValue != toValue && (selfValue == null || !selfValue.Equals(toValue)) && !(selfValue is IEnumerable))
5799
{
58-
return false;
100+
Assert.False(true, $"The property '{pi.Name}' is not equal.");
59101
}
60102
}
61103
}
62104

63-
return true;
105+
return;
64106
}
65107

66-
return a == b;
108+
Assert.Equal(a, b);
67109
}
68110

69111
private static List<ServerPackage> GenerateServerPackages(int count)

0 commit comments

Comments
 (0)