Skip to content

Commit 2b06e03

Browse files
authored
Merge pull request #164 from OmniSharp/fix/uri-serialization
fix/uri-serialization
2 parents 3712f92 + 7497b9c commit 2b06e03

File tree

8 files changed

+108
-1
lines changed

8 files changed

+108
-1
lines changed

src/Protocol/Models/FileEvent.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using Newtonsoft.Json;
33
using Newtonsoft.Json.Serialization;
4+
using OmniSharp.Extensions.LanguageServer.Protocol.Serialization.Converters;
45

56
namespace OmniSharp.Extensions.LanguageServer.Protocol.Models
67
{
@@ -12,7 +13,9 @@ public class FileEvent
1213
/// <summary>
1314
/// The file's URI.
1415
/// </summary>
16+
[JsonConverter(typeof(AbsoluteUriConverter))]
1517
public Uri Uri { get; set; }
18+
1619
/// <summary>
1720
/// The change type.
1821
/// </summary>

src/Protocol/Models/Location.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using Newtonsoft.Json;
44
using Newtonsoft.Json.Serialization;
5+
using OmniSharp.Extensions.LanguageServer.Protocol.Serialization.Converters;
56

67
namespace OmniSharp.Extensions.LanguageServer.Protocol.Models
78
{
@@ -10,6 +11,7 @@ public class Location : IEquatable<Location>
1011
/// <summary>
1112
/// The uri of the document
1213
/// </summary>
14+
[JsonConverter(typeof(AbsoluteUriConverter))]
1315
public Uri Uri { get; set; }
1416

1517
/// <summary>

src/Protocol/Models/PublishDiagnosticsParams.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using OmniSharp.Extensions.Embedded.MediatR;
33
using Newtonsoft.Json;
44
using Newtonsoft.Json.Serialization;
5+
using OmniSharp.Extensions.LanguageServer.Protocol.Serialization.Converters;
56

67
namespace OmniSharp.Extensions.LanguageServer.Protocol.Models
78
{
@@ -10,6 +11,7 @@ public class PublishDiagnosticsParams : IRequest
1011
/// <summary>
1112
/// The URI for which diagnostic information is reported.
1213
/// </summary>
14+
[JsonConverter(typeof(AbsoluteUriConverter))]
1315
public Uri Uri { get; set; }
1416

1517
/// <summary>

src/Protocol/Models/TextDocumentIdentifier.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using Newtonsoft.Json;
33
using Newtonsoft.Json.Serialization;
4+
using OmniSharp.Extensions.LanguageServer.Protocol.Serialization.Converters;
45

56
namespace OmniSharp.Extensions.LanguageServer.Protocol.Models
67
{
@@ -15,9 +16,11 @@ public TextDocumentIdentifier(Uri uri)
1516
{
1617
Uri = uri;
1718
}
19+
1820
/// <summary>
1921
/// The text document's URI.
2022
/// </summary>
23+
[JsonConverter(typeof(AbsoluteUriConverter))]
2124
public Uri Uri { get; set; }
2225
}
2326
}

src/Protocol/Models/WorkspaceFolder.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using Newtonsoft.Json;
3+
using OmniSharp.Extensions.LanguageServer.Protocol.Serialization.Converters;
24

35
namespace OmniSharp.Extensions.LanguageServer.Protocol.Models
46
{
@@ -7,6 +9,7 @@ public class WorkspaceFolder
79
/// <summary>
810
/// The associated URI for this workspace folder.
911
/// </summary>
12+
[JsonConverter(typeof(AbsoluteUriConverter))]
1013
public Uri Uri { get; set; }
1114

1215
/// <summary>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
// #see https://github.com/NuGet/NuGet.Server
4+
using System;
5+
using Newtonsoft.Json;
6+
7+
namespace OmniSharp.Extensions.LanguageServer.Protocol.Serialization.Converters
8+
{
9+
/// <summary>
10+
/// This is necessary because Newtonsoft.Json creates <see cref="Uri"/> instances with
11+
/// <see cref="UriKind.RelativeOrAbsolute"/> which treats UNC paths as relative. NuGet.Core uses
12+
/// <see cref="UriKind.Absolute"/> which treats UNC paths as absolute. For more details, see:
13+
/// https://github.com/JamesNK/Newtonsoft.Json/issues/2128
14+
/// </summary>
15+
class AbsoluteUriConverter : JsonConverter<Uri>
16+
{
17+
public override Uri ReadJson(JsonReader reader, Type objectType, Uri existingValue, bool hasExistingValue, JsonSerializer serializer)
18+
{
19+
if (reader.TokenType == JsonToken.Null)
20+
{
21+
return null;
22+
}
23+
else if (reader.TokenType == JsonToken.String)
24+
{
25+
var uri = new Uri((string)reader.Value, UriKind.RelativeOrAbsolute);
26+
if (!uri.IsAbsoluteUri)
27+
{
28+
throw new JsonSerializationException($"The Uri must be absolute. Given: {reader.Value}");
29+
}
30+
return uri;
31+
}
32+
33+
throw new JsonSerializationException("The JSON value must be a string.");
34+
}
35+
36+
public override void WriteJson(JsonWriter writer, Uri value, JsonSerializer serializer)
37+
{
38+
if (value == null)
39+
{
40+
writer.WriteNull();
41+
return;
42+
}
43+
44+
if (!(value is Uri uriValue))
45+
{
46+
throw new JsonSerializationException("The value must be a URI.");
47+
}
48+
49+
if (!uriValue.IsAbsoluteUri)
50+
{
51+
throw new JsonSerializationException("The URI value must be an absolute Uri. Relative URI instances are not allowed.");
52+
}
53+
54+
writer.WriteValue(uriValue.ToString());
55+
}
56+
}
57+
}

test/Lsp.Tests/Models/TextDocumentIdentifierTests.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,41 @@ public void SimpleTest(string expected)
2222
var deresult = new Serializer(ClientVersion.Lsp3).DeserializeObject<TextDocumentIdentifier>(expected);
2323
deresult.Should().BeEquivalentTo(model);
2424
}
25+
26+
[Fact]
27+
public void Should_Fail_To_Serialize_When_Given_A_Non_Relative_Uri()
28+
{
29+
var serializer = new Serializer(ClientVersion.Lsp3);
30+
var model = new TextDocumentIdentifier()
31+
{
32+
Uri = new Uri("./abc23.cs", UriKind.Relative),
33+
};
34+
35+
Action a = () => serializer.SerializeObject(model);
36+
a.Should().Throw<JsonSerializationException>();
37+
}
38+
39+
[Fact]
40+
public void Should_Fail_To_Deserialize_When_Given_A_Non_Relative_Uri()
41+
{
42+
var serializer = new Serializer(ClientVersion.Lsp3);
43+
var json = @"{
44+
""uri"":""./0b0jnxg2.kgh.ps1""
45+
}";
46+
47+
Action a = () => serializer.DeserializeObject<TextDocumentIdentifier>(json);
48+
a.Should().Throw<JsonSerializationException>();
49+
}
50+
51+
[Fact]
52+
public void Should_Deserialize_For_Example_Value()
53+
{
54+
var serializer = new Serializer(ClientVersion.Lsp3);
55+
var result = serializer.DeserializeObject<TextDocumentIdentifier>(@"{
56+
""uri"":""file:///Users/tyler/Code/PowerShell/vscode/PowerShellEditorServices/test/PowerShellEditorServices.Test.E2E/bin/Debug/netcoreapp2.1/0b0jnxg2.kgh.ps1""
57+
}");
58+
59+
result.Uri.Should().Be(new Uri("file:///Users/tyler/Code/PowerShell/vscode/PowerShellEditorServices/test/PowerShellEditorServices.Test.E2E/bin/Debug/netcoreapp2.1/0b0jnxg2.kgh.ps1", UriKind.Absolute));
60+
}
2561
}
2662
}

test/Lsp.Tests/Models/VersionedTextDocumentIdentifierTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ public class VersionedTextDocumentIdentifierTests
1414
[Theory, JsonFixture]
1515
public void SimpleTest(string expected)
1616
{
17-
var model = new VersionedTextDocumentIdentifier() {
17+
var model = new VersionedTextDocumentIdentifier()
18+
{
1819
Uri = new Uri("file:///abc/123.cs"),
1920
Version = 12
2021
};

0 commit comments

Comments
 (0)