Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Uri] Uri.EscapeUriString should be deprecated #31387

Closed
lostmsu opened this issue Nov 4, 2019 · 17 comments
Closed

[Uri] Uri.EscapeUriString should be deprecated #31387

lostmsu opened this issue Nov 4, 2019 · 17 comments
Assignees
Labels
area-System.Net documentation Documentation bug or enhancement, does not impact product or test code
Milestone

Comments

@lostmsu
Copy link

lostmsu commented Nov 4, 2019

Please, see the relevant StackOveflow thread.

From my understanding of the issue, there is no valid and/or safe use case for EscapeUriString. Either one wants to escape a URI component, in which case they should call EscapeDataString, or they construct URI incorrectly in the first place.

@karelz
Copy link
Member

karelz commented Jan 7, 2020

@MihaZupan can you please look into this one to validate the conclusions above?

@MihaZupan
Copy link
Member

MihaZupan commented Jan 13, 2020

From the linked thread (emphasis mine):

You should always construct your URLs and query strings by gathering the key-value pairs and percent-encoding and then concatenating them with the necessary separators. You can use Uri.EscapeDataString for this purpose, but not Uri.EscapeUriString, since it doesn't escape reserved characters, as mentioned above.

Only if you cannot do that, e.g. when dealing with user-provided URIs, does it make sense to use Uri.EscapeUriString as a last resort. But the previously mentioned caveats apply – if the user-provided URI is ambiguous, the results may not be desirable.

I believe this is a valid use-case. I am not aware of a direct/better alternative for such a scenario, so I don't think the method can be deprecated. The documentation for it could, however, be updated to note its intended usage - if there are other valid usage scenarios for it I would love to know.

@lostmsu
Copy link
Author

lostmsu commented Jan 13, 2020

@MihaZupan so what is a concrete example, in which case EscapeUriString is required over EscapeDataString?

@MihaZupan
Copy link
Member

The two methods have different use-cases.

For example, if you are escaping a query key or value, you should use EscapeDataString.

string uri = "https://foo.bar/?someKey=" + Uri.EscapeDataString(someValue);

But, if you are trying to escape a whole uri, you should not use EscapeDataString as it will encode too much

string userProvidedUri = "http://foo.bar/a b";

string escapeData = Uri.EscapeDataString(userProvidedUri);
// http%3A%2F%2Ffoo.bar%2Fa%20b

string escapeUri = Uri.EscapeUriString(userProvidedUri);
// http://foo.bar/a%20b

That said, I am having trouble finding a uri example where using EscapeUriString is necesarry before passing the string to the ctor.

@lostmsu
Copy link
Author

lostmsu commented Jan 14, 2020

That's exactly the point.

if you are trying to escape a whole uri

If you need to escape a whole URI, what kind of escaping you need to do depends on what are you escaping for.

I suspect (and it might have been mentioned in the original post), that the whole URI might had a need to be escaped for certain browsers which did not support spaces or, for example, instant messengers, which would confuse a space in plain text as a URI's end. But this escaping is highly specific to a concrete browser/IM/other software use case. And EscapeUriString can not be a universal tool: there is no specific standard it adheres to.

What's a real problem though, is that its presence makes it confusing to pick from EscapeDataString and EscapeUriString, as the docs have trouble explaining the difference (in fact, at the moment the docs for the two look semantically identical, sort of proving the point).

https://docs.microsoft.com/en-us/dotnet/api/system.uri.escapeuristring
https://docs.microsoft.com/en-us/dotnet/api/system.uri.escapedatastring

It even has this line "Use the EscapeUriString method to prepare an unescaped URI string to be a parameter to the Uri constructor." And with your example it is clear, that it is outdated, as new Uri("http://foo.bar/a b") works perfectly fine.

@lostmsu
Copy link
Author

lostmsu commented Jan 14, 2020

To further illustrate the problem, just look at this: https://github.com/search?q=EscapeUriString&type=Code

I struggled to find any code example there, in which EscapeUriString would not lead to incorrect input processing under some circumstances discussed in SO thread.

@karelz karelz changed the title Uri.EscapeUriString should be deprecated [Uri] Uri.EscapeUriString should be deprecated Jan 21, 2020
@msftgits msftgits transferred this issue from dotnet/corefx Feb 1, 2020
@karelz karelz added the untriaged New issue has not been triaged by the area owner label Feb 22, 2020
@karelz
Copy link
Member

karelz commented Mar 5, 2020

Triage: We should likely make it part of Roslyn Analyzers. @MihaZupan can you please summarize our approach and recommendation.
Overall we don't believe most people are using it correctly.

@karelz karelz added documentation Documentation bug or enhancement, does not impact product or test code and removed untriaged New issue has not been triaged by the area owner labels Mar 5, 2020
@karelz karelz added this to the 5.0 milestone Mar 5, 2020
@lostmsu
Copy link
Author

lostmsu commented Mar 5, 2020

@karelz I think Roslyn Analyzers is insufficient, as they are rarely used. It should at very least be marked with [Obsolete].

Here's another link, that might convince you: https://github.com/search?q=org%3Amicrosoft+EscapeUriString&type=Code

I see one in Microsoft/Docker.DotNet

@karelz
Copy link
Member

karelz commented Mar 5, 2020

@lostmsu we have plans to add default Roslyn Analyzers. The rule would be default if 99% cases are incorrectly used. If it is more than that, we may have to make the rule off by default.
Bringing false positives to devs is troublesome -- no matter if it is Obsolete or Analyzer. Analyzers have the nice property of ability to be updated and fine-tuned if necessary.

@karelz
Copy link
Member

karelz commented Aug 27, 2020

@aik-jahoda please add the Obsolete attribute, @MihaZupan will help with writing the right docs later.

@aik-jahoda
Copy link
Contributor

aik-jahoda commented Aug 28, 2020

@karelz karelz modified the milestones: 5.0.0, 6.0.0 Aug 31, 2020
@karelz
Copy link
Member

karelz commented Aug 31, 2020

Moving to 6.0 -- we won't backport it to 5.0 this late in the game.

@karelz
Copy link
Member

karelz commented Feb 12, 2021

@MihaZupan That said, I am having trouble finding a uri example where using EscapeUriString is necesarry before passing the string to the ctor.

Just found a corner case where it differs:

Console.WriteLine(new Uri("http://my/%20").AbsoluteUri);                      // Output: http://my/%20
Console.WriteLine(new Uri(Uri.EscapeUriString("http://my/%20")).AbsoluteUri); // Output: http://my/%2520

Console.WriteLine(new Uri("http://my/%23").AbsoluteUri);                      // Output: http://my/%23
Console.WriteLine(new Uri(Uri.EscapeUriString("http://my/%23")).AbsoluteUri); // Output: http://my/%2523

@jeffhandley
Copy link
Member

@karelz I'm moving this to 7.0 (along with some other obsoletions). Feel free to pull this back into 6.0 if you were still planning to do this for RC1.

@jeffhandley jeffhandley modified the milestones: 6.0.0, 7.0.0 Jul 31, 2021
@karelz
Copy link
Member

karelz commented Jul 31, 2021

@jeffhandley given that this is missing just docs, I think it makes sense to have it in 6.0. I expect that docs will happen post RC1 fork ...

@karelz karelz removed this from the 7.0.0 milestone Jul 31, 2021
@karelz karelz added this to the 6.0.0 milestone Jul 31, 2021
@jeffhandley
Copy link
Member

Ah; cool. I overlooked that aspect. Thanks.

@MihaZupan
Copy link
Member

MihaZupan commented Aug 23, 2021

The documentation effort seems to be complete here, I linked the relevant PRs where changes happened in #31387 (comment). Closing.

@MihaZupan That said, I am having trouble finding a uri example where using EscapeUriString is necesarry before passing the string to the ctor.

Just found a corner case where it differs:
"http://my/%20" vs EscapeUriString("http://my/%20")

The output may differ, but the Uri ctor will accept the value regardless. Escaping the % to %25 is most likely an unintended consequence of using EscapeUriString for the user.

@ghost ghost locked as resolved and limited conversation to collaborators Sep 22, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Net documentation Documentation bug or enhancement, does not impact product or test code
Projects
None yet
Development

No branches or pull requests

5 participants