[PTRun][URL]Fix web link with ports support (#19809)

* [PT Run] Fix web link with ports support (#14260)

* URL in the format of `domain:port` now directs to default browser

* Add tests to verify web link with ports scenario

* Fix test case and scenario where mismatching schema and port for IPv6 does not result in correct output

* [PT Run][Tests] Change and add more UriParser Tests

* Specifically of note is line 56, where [IPv6]:80 diverts to https instead of http.

* [PT Run][Tests] Add UriParser tests

* Add more tests targeting port handling

* [PT Run] Fix http handling

* This also fixes oddity with IPv4 and IPv6 handling

* [PT Run] Add second results depending on condition

* Test: update all test to reflect updated functions & add a little more tests

* Update function to show two results when URI is in the format of `domain:port` (situation where it can also be `schema:path`)

* Update regex style to follow previous code

* [PT Run] Change tests and filter localhost from certain results

* Add tests for 127.0.0.1, localhost, and ::1

* Move test around into more logical arrangement

* Filter localhost out from showing double results

* [PT Run] Fix spelling on comments

* [PT Run] Add some words to expect.txt

* [PT Toys] Clarify comment regarding [::]

Co-authored-by: Heiko <61519853+htcfreek@users.noreply.github.com>

* [PT Run] Remove tests regarding tel protocol

* [PT Run] Clarify UriParser parameter

* [PT Run] Add UriParser tests for tel protocol

* Current code has a regression bug where tel:xxxx, if xxxx is more than 65536 it will break. Will fix in follow up commit.

* [PT Run] Refactor ExtendedUriParser and its tests

* Remove `isWebUri` from ExtendedUriParser, keeping only webUri and systemUri

* Tel protocol regression bug still exists

* [PT Run] Fix wrong icon when webUri result

* [PT Run] Fix regression bug for tel protocol

* Tel protocol will sometimes bug out when tel:xxxx if xxxxx is more than 65535, as UriBuilder will throw error thinking the port number has been exceeded

* [PT Toy] Fix tel test

* [PT Run] Changes to tests

* Add test for application uri to include ports, for all non-protocol, http and https variants

* Rearrange some more test to make more logical sense, and add comments

* [PT Run] Simplify code

* Move webUri and systemUri to be global, as per htcfreek's recommendation

* Add comment to empty catch

* Change null to default

* [PT Toy] Update test name

Co-authored-by: Heiko <61519853+htcfreek@users.noreply.github.com>

* [PT Toy] Change result prompt when empty string

* [PT Toy] Fix typo in comment

* [PT Toy] Simplify line

* [PT Toy] Change result prompt when empty string
This commit is contained in:
Koh Jun Dong
2022-08-12 00:04:39 +08:00
committed by GitHub
parent c0217a3cc4
commit efa09182d3
5 changed files with 245 additions and 118 deletions

View File

@@ -6,6 +6,6 @@ namespace Microsoft.Plugin.Uri.Interfaces
{
public interface IUriParser
{
bool TryParse(string input, out System.Uri result, out bool isWebUri);
bool TryParse(string input, out System.Uri webUri, out System.Uri systemUri);
}
}

View File

@@ -50,7 +50,7 @@ namespace Microsoft.Plugin.Uri
{
results.Add(new Result
{
Title = Properties.Resources.Microsoft_plugin_uri_open,
Title = Properties.Resources.Microsoft_plugin_uri_default_browser,
SubTitle = BrowserInfo.Path,
IcoPath = DefaultIconPath,
Action = action =>
@@ -70,34 +70,54 @@ namespace Microsoft.Plugin.Uri
}
if (!string.IsNullOrEmpty(query?.Search)
&& _uriParser.TryParse(query.Search, out var uriResult, out var isWebUri)
&& _uriResolver.IsValidHost(uriResult))
&& _uriParser.TryParse(query.Search, out var webUriResult, out var systemUriResult)
&& _uriResolver.IsValidHost(webUriResult))
{
var uriResultString = uriResult.ToString();
var isWebUriBool = isWebUri;
results.Add(new Result
if (webUriResult is not null)
{
Title = uriResultString,
SubTitle = isWebUriBool
? Properties.Resources.Microsoft_plugin_uri_website
: Properties.Resources.Microsoft_plugin_uri_open,
IcoPath = isWebUriBool && BrowserInfo.IconPath != null
? BrowserInfo.IconPath
: DefaultIconPath,
Action = action =>
var resultString = webUriResult.ToString();
results.Add(new Result
{
if (!Helper.OpenInShell(uriResultString))
Title = resultString,
SubTitle = Properties.Resources.Microsoft_plugin_uri_website,
IcoPath = BrowserInfo.IconPath,
Action = action =>
{
var title = $"Plugin: {Properties.Resources.Microsoft_plugin_uri_plugin_name}";
var message = $"{Properties.Resources.Microsoft_plugin_uri_open_failed}: {uriResultString}";
Context.API.ShowMsg(title, message);
return false;
}
if (!Helper.OpenInShell(resultString))
{
var title = $"Plugin: {Properties.Resources.Microsoft_plugin_uri_plugin_name}";
var message = $"{Properties.Resources.Microsoft_plugin_uri_open_failed}: {resultString}";
Context.API.ShowMsg(title, message);
return false;
}
return true;
},
});
return true;
},
});
}
if (systemUriResult is not null)
{
var resultString = systemUriResult.ToString();
results.Add(new Result
{
Title = resultString,
SubTitle = Properties.Resources.Microsoft_plugin_uri_open,
IcoPath = DefaultIconPath,
Action = action =>
{
if (!Helper.OpenInShell(resultString))
{
var title = $"Plugin: {Properties.Resources.Microsoft_plugin_uri_plugin_name}";
var message = $"{Properties.Resources.Microsoft_plugin_uri_open_failed}: {resultString}";
Context.API.ShowMsg(title, message);
return false;
}
return true;
},
});
}
}
return results;

View File

@@ -12,18 +12,19 @@ namespace Microsoft.Plugin.Uri.UriHelper
public class ExtendedUriParser : IUriParser
{
// When updating this method, also update the local method IsUri() in Community.PowerToys.Run.Plugin.WebSearch.Main.Query
public bool TryParse(string input, out System.Uri result, out bool isWebUri)
public bool TryParse(string input, out System.Uri webUri, out System.Uri systemUri)
{
webUri = default;
systemUri = default;
if (string.IsNullOrEmpty(input))
{
result = default;
isWebUri = false;
return false;
}
// Handling URL with only scheme, typically mailto or application uri.
// Do nothing, return the result without urlBuilder
// And check if scheme match REC3986 (issue #15035)
// And check if scheme match RFC3986 (issue #15035)
const string schemeRegex = @"^([a-z][a-z0-9+\-.]*):";
if (input.EndsWith(":", StringComparison.OrdinalIgnoreCase)
&& !input.StartsWith("http", StringComparison.OrdinalIgnoreCase)
@@ -31,8 +32,7 @@ namespace Microsoft.Plugin.Uri.UriHelper
&& !input.All(char.IsDigit)
&& Regex.IsMatch(input, schemeRegex))
{
result = new System.Uri(input);
isWebUri = false;
systemUri = new System.Uri(input);
return true;
}
@@ -44,42 +44,66 @@ namespace Microsoft.Plugin.Uri.UriHelper
|| input.EndsWith("://", StringComparison.CurrentCulture)
|| input.All(char.IsDigit))
{
result = default;
isWebUri = false;
return false;
}
try
{
string isDomainPortRegex = @"^[\w\.]+:\d+";
string isIPv6PortRegex = @"^\[([\w:]+:+)+[\w]+\]:\d+";
var urlBuilder = new UriBuilder(input);
var hadDefaultPort = urlBuilder.Uri.IsDefaultPort;
urlBuilder.Port = hadDefaultPort ? -1 : urlBuilder.Port;
urlBuilder.Port = urlBuilder.Uri.IsDefaultPort ? -1 : urlBuilder.Port;
if (input.StartsWith("HTTP://", StringComparison.OrdinalIgnoreCase))
{
urlBuilder.Scheme = System.Uri.UriSchemeHttp;
isWebUri = true;
}
else if (Regex.IsMatch(input, isDomainPortRegex) ||
Regex.IsMatch(input, isIPv6PortRegex))
{
var secondUrlBuilder = urlBuilder;
try
{
urlBuilder = new UriBuilder("https://" + input);
if (urlBuilder.Port == 80)
{
urlBuilder.Scheme = System.Uri.UriSchemeHttp;
}
}
catch (UriFormatException)
{
// This handles the situation in tel:xxxx and others
// When xxxx > 65535, it will throw UriFormatException
// The catch ensures it will at least still try to return a systemUri
}
string singleLabelRegex = @"[\.:]+|^http$|^https$|^localhost$";
systemUri = Regex.IsMatch(urlBuilder.Host, singleLabelRegex) ? null : secondUrlBuilder.Uri;
}
else if (input.Contains(':', StringComparison.OrdinalIgnoreCase) &&
!input.StartsWith("http", StringComparison.OrdinalIgnoreCase) &&
!input.Contains('[', StringComparison.OrdinalIgnoreCase))
{
// Do nothing, leave unchanged
isWebUri = false;
systemUri = urlBuilder.Uri;
}
else
{
urlBuilder.Scheme = System.Uri.UriSchemeHttps;
isWebUri = true;
}
result = urlBuilder.Uri;
if (urlBuilder.Scheme.Equals(System.Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase) ||
urlBuilder.Scheme.Equals(System.Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase))
{
webUri = urlBuilder.Uri;
}
return true;
}
catch (UriFormatException)
{
result = default;
isWebUri = false;
return false;
}
}