Skip to content

[BUG] System.Uri cannot parse certain URIs #7638

Closed
dotnet/roslyn
#76691
@dibarbet

Description

@dibarbet

Summary

Certain kinds of URIs that are RFC spec valid URIs are not parseable by System.Uri. The main case for this is if there are sub-delims in the host name. Some examples of when we get this

  1. Perforce for VS Code will sometimes have # percent encoded in the host name.
  2. Notebook URIs provided by VSCode when running in a devcontainer can have + in the URI (Microsoft.CodeAnalysis.LanguageServer server crashed 5 times in the last 3 minutes #7630 (comment))

Both of these are caused by dotnet/runtime#64707 - System.Uri does extra host name validation beyond what the RFC spec indicates.

Since we can't deserialize, we throw exceptions and the server crashes if the file is opened (we can't handle the didOpen request). To solve this, we have a few different paths forward:

  1. Push on the runtime to allow a parsing mode that is fully RFC spec compliant and does not do extra host name validation.
    a. This would only apply to newer runtimes, so if implemented today, the earliest we could use it when we switch to the .NET 10 runtime.
  2. Remove usages of System.Uri entirely and do our own URI parsing (O# does this - https://github.com/OmniSharp/csharp-language-server-protocol/blob/master/src/Protocol/DocumentUri.cs)
    a. This is fairly complicated to get right, and we have to maintain our own URI parser.
  3. Remove usages of System.Uri in our protocol serialization types (use string, or wrapper for string). Only when we need to actually parse the URI to find the file path do we call out to System.Uri to parse it. This would allow us to handle the normal text sync requests for these documents and prevent the server from crashing. Only individual requests would fail when we try and find the document in the sln.
Original perforce issue text

Describe the Issue

When enable the extention plugin "Perforce for VS Code", the total function will not work and it says:

[stdout] {"pipeName":"\\\\.\\pipe\\6801cf8c"}
received named pipe information from server
attempting to connect client to server...
client has connected to server
[Info  - 10:43:39 AM] [Program] Language server initialized
[Error - 10:43:40 AM] [LanguageServerHost] System.UriFormatException: Invalid URI: The hostname could not be parsed.
   at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind, UriCreationOptions& creationOptions)
   at System.Uri..ctor(String uriString)
   at Roslyn.LanguageServer.Protocol.DocumentUriConverter.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options) in /_/src/LanguageServer/Protocol/Protocol/Converters/DocumentUriConverter.cs:line 17
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
   at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 utf8Json, JsonTypeInfo`1 jsonTypeInfo, Nullable`1 actualByteCount)
   at System.Text.Json.JsonSerializer.Deserialize[TValue](JsonElement element, JsonSerializerOptions options)
   at Microsoft.CommonLanguageServerProtocol.Framework.SystemTextJsonLanguageServer`1.DeserializeRequest[TRequest](Object serializedRequest, RequestHandlerMetadata metadata) in /_/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/SystemTextJsonLanguageServer.cs:line 50
   at Microsoft.CommonLanguageServerProtocol.Framework.QueueItem`1.TryDeserializeRequest[TRequest](AbstractLanguageServer`1 languageServer, RequestHandlerMetadata requestHandlerMetadata, Boolean isMutating, TRequest& request) in /_/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/QueueItem.cs:line 117
[Error - 10:43:40 AM] [LanguageServerHost] System.UriFormatException: Invalid URI: The hostname could not be parsed.
   at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind, UriCreationOptions& creationOptions)
   at System.Uri..ctor(String uriString)
   at Roslyn.LanguageServer.Protocol.DocumentUriConverter.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options) in /_/src/LanguageServer/Protocol/Protocol/Converters/DocumentUriConverter.cs:line 17
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
   at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 utf8Json, JsonTypeInfo`1 jsonTypeInfo, Nullable`1 actualByteCount)
   at System.Text.Json.JsonSerializer.Deserialize[TValue](JsonElement element, JsonSerializerOptions options)
   at Microsoft.CommonLanguageServerProtocol.Framework.SystemTextJsonLanguageServer`1.DeserializeRequest[TRequest](Object serializedRequest, RequestHandlerMetadata metadata) in /_/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/SystemTextJsonLanguageServer.cs:line 50
   at Microsoft.CommonLanguageServerProtocol.Framework.QueueItem`1.TryDeserializeRequest[TRequest](AbstractLanguageServer`1 languageServer, RequestHandlerMetadata requestHandlerMetadata, Boolean isMutating, TRequest& request) in /_/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/QueueItem.cs:line 117
--- End of stack trace from previous location ---
   at Microsoft.CommonLanguageServerProtocol.Framework.AbstractLanguageServer`1.DelegatingEntryPoint.InvokeAsync(IRequestExecutionQueue`1 queue, Object requestObject, ILspServices lspServices, CancellationToken cancellationToken) in /_/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/AbstractLanguageServer.cs:line 202
   at Microsoft.CommonLanguageServerProtocol.Framework.SystemTextJsonLanguageServer`1.SystemTextJsonDelegatingEntryPoint.ExecuteRequestAsync(Nullable`1 request, CancellationToken cancellationToken) in /_/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/SystemTextJsonLanguageServer.cs:line 88
   at Microsoft.CommonLanguageServerProtocol.Framework.QueueItem`1.CreateRequestContextAsync[TRequest](IMethodHandler handler, RequestHandlerMetadata requestHandlerMetadata, AbstractLanguageServer`1 languageServer, CancellationToken cancellationToken)
   at Microsoft.CommonLanguageServerProtocol.Framework.RequestExecutionQueue`1.ProcessQueueCoreAsync[TRequest,TResponse](IQueueItem`1 work, IMethodHandler handler, RequestHandlerMetadata metadata, ConcurrentDictionary`2 concurrentlyExecutingTasks, CancellationTokenSource currentWorkCts, CancellationToken cancellationToken) in /_/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/RequestExecutionQueue.cs:line 319
   at Microsoft.CommonLanguageServerProtocol.Framework.RequestExecutionQueue`1.InvokeProcessCoreAsync(IQueueItem`1 work, RequestHandlerMetadata metadata, IMethodHandler handler, MethodInfo methodInfo, ConcurrentDictionary`2 concurrentlyExecutingTasks, CancellationTokenSource currentWorkCts, CancellationToken cancellationToken) in /_/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/RequestExecutionQueue.cs:line 302
   at Microsoft.CommonLanguageServerProtocol.Framework.RequestExecutionQueue`1.ProcessQueueAsync() in /_/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/RequestExecutionQueue.cs:line 254
[Info  - 10:43:40 AM] Error processing queue, shutting down
[Error - 10:43:40 AM] Workspace diagnostic pull failed.
Canceled: Canceled
	at a.handleFailedRequest (c:\Users\zhentao.wang\.vscode\extensions\ms-dotnettools.csharp-2.45.25-win32-x64\dist\extension.js:2:2137527)
	at a.handleFailedRequest (c:\Users\zhentao.wang\.vscode\extensions\ms-dotnettools.csharp-2.45.25-win32-x64\dist\extension.js:2:1253271)
	at c:\Users\zhentao.wang\.vscode\extensions\ms-dotnettools.csharp-2.45.25-win32-x64\dist\extension.js:2:2174939
	at async g.pullWorkspaceAsync (c:\Users\zhentao.wang\.vscode\extensions\ms-dotnettools.csharp-2.45.25-win32-x64\dist\extension.js:2:2172247)
[Error - 10:43:40 AM] Workspace diagnostic pull failed.
Canceled: Canceled
	at a.handleFailedRequest (c:\Users\zhentao.wang\.vscode\extensions\ms-dotnettools.csharp-2.45.25-win32-x64\dist\extension.js:2:2137527)
	at a.handleFailedRequest (c:\Users\zhentao.wang\.vscode\extensions\ms-dotnettools.csharp-2.45.25-win32-x64\dist\extension.js:2:1253271)
	at c:\Users\zhentao.wang\.vscode\extensions\ms-dotnettools.csharp-2.45.25-win32-x64\dist\extension.js:2:2174939
	at runNextTicks (node:internal/process/task_queues:60:5)
	at process.processImmediate (node:internal/timers:449:9)
	at async g.pullWorkspaceAsync (c:\Users\zhentao.wang\.vscode\extensions\ms-dotnettools.csharp-2.45.25-win32-x64\dist\extension.js:2:2172247)
[Error - 10:43:40 AM] Workspace diagnostic pull failed.
Canceled: Canceled
	at a.handleFailedRequest (c:\Users\zhentao.wang\.vscode\extensions\ms-dotnettools.csharp-2.45.25-win32-x64\dist\extension.js:2:2137527)
	at a.handleFailedRequest (c:\Users\zhentao.wang\.vscode\extensions\ms-dotnettools.csharp-2.45.25-win32-x64\dist\extension.js:2:1253271)
	at c:\Users\zhentao.wang\.vscode\extensions\ms-dotnettools.csharp-2.45.25-win32-x64\dist\extension.js:2:2174939
	at runNextTicks (node:internal/process/task_queues:60:5)
	at process.processImmediate (node:internal/timers:449:9)
	at async g.pullWorkspaceAsync (c:\Users\zhentao.wang\.vscode\extensions\ms-dotnettools.csharp-2.45.25-win32-x64\dist\extension.js:2:2172247)
[Error - 10:43:40 AM] Request textDocument/diagnostic failed.
  Message: Server was requested to shut down.
  Code: -32000

Steps To Reproduce

  1. Download and Enable "Perforce for Vs Code"
  2. Open the c# project
  3. The error pops up and c# Dev kit cannot work

Expected Behavior

No response

Environment Information

Windows, C# Dev Kit v1.10.18, Perforce for VS Code v4.15.7

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions