Repository navigation
Conversation
|
Azure Pipelines: Successfully started running 4 pipeline(s). 12 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
1 similar comment
|
Azure Pipelines: Successfully started running 4 pipeline(s). 12 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
| { | ||
| // Try raw compare for _strings as the last chance to keep the working set small | ||
| if (string.Equals(_string, other._string, IsUncOrDosPath ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) | ||
| // Simple IPv6 parsers must keep scope IDs case-sensitive, even for file URIs. |
There was a problem hiding this comment.
Do we have tests for all the added IsSimple checks?
There was a problem hiding this comment.
The hash and final scope-comparison checks are covered by the simple-parser tests and the custom/custom and custom/simple comparisons, including hash stability after accessing IdnHost. However, the non-simple file-style case for the raw-string shortcut is missing. I propose adding a focused test for that branch.
Update:
On closer inspection, the raw-string shortcut's IsSimple check is redundant: FileStyleUriParser, including derived types, inherits SimpleUserSyntax from the built-in file parser. I removed that check. The file-URI cases added to the existing equality test cover the raw-string shortcut, and the existing simple-parser and custom-parser tests cover the remaining IsSimple checks.
| // Custom parsers define identity through HttpRequestUrl and may return it without | ||
| // initializing the host. ScopeId can remain null until Host or IdnHost is accessed, | ||
| // so including it could change the hash after those properties populate the cache. |
There was a problem hiding this comment.
Should we ensure it's initialized in that case?
There was a problem hiding this comment.
Ensuring initialization consistently would address the lazy-cache issue. My reason for the IsSimple guard is compatibility: for a non-simple parser, forcing host initialization via EnsureHostString(false) can invoke both Host and StrongPort callbacks and trigger additional validation.
Including the initialized scope would also change custom-parser equality, rather than merely stabilize the cache. The current patch preserves that behavior, though it also leaves non-simple derived parsers that simply delegate to the base implementation unchanged. I would prefer to retain that compatibility boundary unless we intend to extend the scope change to non-simple parsers as well.
There was a problem hiding this comment.
The relevant code path is that IsSimple selects GetComponentsHelper, whereas non-simple parsers dispatch to the overridable GetComponents implementation. Since HttpRequestUrl includes Host, the standard formatter calls EnsureHostString. For a scoped IPv6 host, this initializes the host and scope as part of generating the comparison/hash representation. A custom override can return that representation without taking this path.
Note
This reply was drafted with GitHub Copilot.
Motivation
Uri.EqualsandUri.GetHashCodeuse a cached representation based onUriComponents.HttpRequestUrl, which omits IPv6 scope IDs. Consequently, URIs such ashttp://[fe80::1%1]/andhttp://[fe80::1%2]/can compare equal despite identifying different local network zones.This affects consumers that use
Urias a key. InSocketsHttpHandler, changing a proxy's IPv6 scope can reuse the previous proxy's connection pool and select the wrong connection endpoint. This change fixes URI identity at the source rather than introducing a handler-specific workaround.Approach
%0, without resolving interface names or normalizing scope values.HttpRequestUrlwithout initializing the host or scope cache; including that lazy cache could change a URI's hash after accessing host properties.HttpRequestUrlcontinues to omit scope IDs. Scope identifies a local network zone and is needed for connection selection, but should not be transmitted as part of an outgoing HTTP URI. The fix separates local URI identity from that request representation.Testing
Local validation used Linux x64 through WSL, with Debug library/test builds and the existing Release CoreCLR runtime.
System.Private.Urifunctional inner-loop suiteSystem.Private.Uriunit suiteIsWinHttpHandler-specific skipURI coverage includes scope differences, absent scope versus
%0, equivalent IPv6 representations, file URI semantics, disabled path/query canonicalization, registered simple parsers, and custom-parser equality/hash stability.The proxy regressions verify that changing scope selects the new proxy endpoint. The HTTPS case checks endpoint selection before TLS, not a completed TLS handshake. All three proxy cases fail against the original
Uriimplementation, selecting%1when%2is expected. The focused URI run against the original implementation also produced seven expected failures.Resolves #135103
Note
This description was generated with GitHub Copilot.