Skip to content

Commit fa652bf

Browse files
Updates version to v4.0.0 (#1875)
* Updates version to v4.0.0 * Fix v4 schema references Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Fix Edge Beta and IPv6 support Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Fix IPv6 proxy address formatting Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Normalize wildcard proxy addresses Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Preserve explicit API ports Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Normalize bracketed IPv6 addresses Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 0f702b9 commit fa652bf

33 files changed

Lines changed: 178 additions & 86 deletions

‎DevProxy.Abstractions.Tests/Proxy/SystemProxyAddressTests.cs‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ public class SystemProxyAddressTests
1515
[InlineData(" ")]
1616
[InlineData("0.0.0.0")]
1717
[InlineData("::")]
18+
[InlineData("::0")]
19+
[InlineData("0:0:0:0:0:0:0:0")]
20+
[InlineData("[::]")]
1821
public void ResolveHost_WildcardOrEmpty_CollapsesToLoopback(string? ipAddress) =>
1922
Assert.Equal("127.0.0.1", SystemProxyAddress.ResolveHost(ipAddress));
2023

@@ -33,6 +36,27 @@ public void ToHostPort_ComposesNormalizedHostAndPort() =>
3336
public void ToHostPort_ExplicitAddress() =>
3437
Assert.Equal("10.0.0.5:9090", SystemProxyAddress.ToHostPort("10.0.0.5", 9090));
3538

39+
[Fact]
40+
public void ToHostPort_ExplicitIpv6Address_UsesBrackets() =>
41+
Assert.Equal("[::1]:9090", SystemProxyAddress.ToHostPort("::1", 9090));
42+
43+
[Fact]
44+
public void ToHttpAuthority_Ipv6Address_UsesBrackets() =>
45+
Assert.Equal("http://[::1]:9090", SystemProxyAddress.ToHttpAuthority("::1", 9090));
46+
47+
[Fact]
48+
public void ToHttpAuthority_DefaultHttpPort_IsPreserved() =>
49+
Assert.Equal("http://127.0.0.1:80", SystemProxyAddress.ToHttpAuthority("127.0.0.1", 80));
50+
51+
[Theory]
52+
[InlineData("0.0.0.0")]
53+
[InlineData("::")]
54+
[InlineData("::0")]
55+
[InlineData("0:0:0:0:0:0:0:0")]
56+
[InlineData("[::]")]
57+
public void ToHttpAuthority_WildcardAddress_UsesLoopback(string ipAddress) =>
58+
Assert.Equal("http://127.0.0.1:9090", SystemProxyAddress.ToHttpAuthority(ipAddress, 9090));
59+
3660
[Fact]
3761
public void ToHostPort_NullAddress_UsesLoopback() =>
3862
Assert.Equal("127.0.0.1:8080", SystemProxyAddress.ToHostPort(null, 8080));

‎DevProxy.Abstractions/Proxy/SystemProxyAddress.cs‎

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System.Globalization;
6+
using System.Net;
7+
using System.Net.Sockets;
68

79
namespace DevProxy.Abstractions.Proxy;
810

@@ -33,12 +35,35 @@ public static string ResolveHost(string? ipAddress)
3335
return "127.0.0.1";
3436
}
3537

36-
return ipAddress is "0.0.0.0" or "::" ? "127.0.0.1" : ipAddress;
38+
var host = ipAddress;
39+
if (host.Length > 1 && host[0] == '[' && host[^1] == ']')
40+
{
41+
host = host[1..^1];
42+
}
43+
44+
if (IPAddress.TryParse(host, out var address) &&
45+
(address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any)))
46+
{
47+
return "127.0.0.1";
48+
}
49+
50+
return host;
3751
}
3852

53+
public static string ToHttpAuthority(string? ipAddress, int port) =>
54+
$"{Uri.UriSchemeHttp}://{ToHostPort(ipAddress, port)}";
55+
3956
/// <summary>
4057
/// The <c>host:port</c> value used for the Windows <c>ProxyServer</c> registry setting.
4158
/// </summary>
42-
public static string ToHostPort(string? ipAddress, int port) =>
43-
$"{ResolveHost(ipAddress)}:{port.ToString(CultureInfo.InvariantCulture)}";
59+
public static string ToHostPort(string? ipAddress, int port)
60+
{
61+
var host = ResolveHost(ipAddress);
62+
if (IPAddress.TryParse(host, out var address) && address.AddressFamily == AddressFamily.InterNetworkV6)
63+
{
64+
host = $"[{host}]";
65+
}
66+
67+
return $"{host}:{port.ToString(CultureInfo.InvariantCulture)}";
68+
}
4469
}

‎DevProxy.Plugins/Inspection/DevToolsPlugin.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -861,7 +861,7 @@ private string GetBrowserPath()
861861
PreferredBrowser.Chrome => "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
862862
PreferredBrowser.Edge => "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
863863
PreferredBrowser.EdgeDev => "/Applications/Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Dev",
864-
PreferredBrowser.EdgeBeta => "/Applications/Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Beta",
864+
PreferredBrowser.EdgeBeta => "/Applications/Microsoft Edge Beta.app/Contents/MacOS/Microsoft Edge Beta",
865865
_ => throw new NotSupportedException($"{Configuration.PreferredBrowser} is an unsupported browser. Please change your PreferredBrowser setting for {Name}.")
866866
};
867867
}

‎DevProxy.Plugins/Mocking/MockStdioResponsePlugin.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public sealed class MockStdioResponseConfiguration
3232
public bool NoMocks { get; set; }
3333

3434
[JsonPropertyName("$schema")]
35-
public string Schema { get; set; } = "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.1.0/mockstdioresponseplugin.mocksfile.schema.json";
35+
public string Schema { get; set; } = "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v4.0.0/mockstdioresponseplugin.mocksfile.schema.json";
3636
}
3737

3838
public class MockStdioResponsePlugin(

‎DevProxy.Tests/ConsoleHotkeyHandlerTests.cs‎

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ namespace DevProxy.Tests;
1515
public sealed class ConsoleHotkeyHandlerTests
1616
{
1717
private static (ConsoleHotkeyHandler handler, FakeProxyStateController controller, RecordingConsole console)
18-
CreateHandler(OutputFormat output = OutputFormat.Text)
18+
CreateHandler(OutputFormat output = OutputFormat.Text, string ipAddress = "127.0.0.1")
1919
{
2020
var controller = new FakeProxyStateController();
2121
var console = new RecordingConsole();
22-
var configuration = new FakeProxyConfiguration { Output = output };
22+
var configuration = new FakeProxyConfiguration { Output = output, IPAddress = ipAddress };
2323
var handler = new ConsoleHotkeyHandler(controller, configuration, console);
2424
return (handler, controller, console);
2525
}
@@ -125,6 +125,26 @@ public void PrintApiInstructions_WritesAllApiCommands()
125125
Assert.Contains("/proxy/stopProxy", joined, StringComparison.Ordinal);
126126
}
127127

128+
[Fact]
129+
public void PrintApiInstructions_FormatsIpv6Address()
130+
{
131+
var (handler, _, console) = CreateHandler(OutputFormat.Json, "::1");
132+
133+
handler.PrintApiInstructions();
134+
135+
Assert.Contains(console.Lines, line => line.Contains("http://[::1]:8897/proxy", StringComparison.Ordinal));
136+
}
137+
138+
[Fact]
139+
public void PrintApiInstructions_NormalizesIpv6WildcardAddress()
140+
{
141+
var (handler, _, console) = CreateHandler(OutputFormat.Json, "::");
142+
143+
handler.PrintApiInstructions();
144+
145+
Assert.Contains(console.Lines, line => line.Contains("http://127.0.0.1:8897/proxy", StringComparison.Ordinal));
146+
}
147+
128148
[Fact]
129149
public void PrintBanner_TextMode_PrintsHotkeys()
130150
{

‎DevProxy/Commands/ApiCommand.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ private void PrintApiInfo(OutputFormat outputFormat)
4343
{
4444
var ipAddress = _proxyConfiguration.IPAddress;
4545
var apiPort = _proxyConfiguration.ApiPort;
46-
var baseUrl = $"http://{ipAddress}:{apiPort}";
46+
var baseUrl = SystemProxyAddress.ToHttpAuthority(ipAddress, apiPort);
4747

4848
var endpoints = new[]
4949
{

‎DevProxy/Commands/DevProxyCommand.cs‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ public DevProxyCommand(
243243
IProxyConfiguration proxyConfiguration,
244244
IServiceProvider serviceProvider,
245245
UpdateNotification updateNotification,
246-
ILogger<DevProxyCommand> logger) : base($"Start Dev Proxy\n\nAPI:\n Dev Proxy exposes a REST API for runtime management.\n OpenAPI spec: http://{proxyConfiguration.IPAddress ?? "127.0.0.1"}:{proxyConfiguration.ApiPort}/swagger\n Use --api-port to configure (default: {proxyConfiguration.ApiPort}).\n Run 'devproxy api show' for more information.")
246+
ILogger<DevProxyCommand> logger) : base($"Start Dev Proxy\n\nAPI:\n Dev Proxy exposes a REST API for runtime management.\n OpenAPI spec: {SystemProxyAddress.ToHttpAuthority(proxyConfiguration.IPAddress, proxyConfiguration.ApiPort)}/swagger\n Use --api-port to configure (default: {proxyConfiguration.ApiPort}).\n Run 'devproxy api show' for more information.")
247247
{
248248
_serviceProvider = serviceProvider;
249249
_plugins = plugins;
@@ -313,7 +313,10 @@ private async Task<int> InvokeAsync(ParseResult parseResult, CancellationToken c
313313
_app.Lifetime.ApplicationStarted.Register(() =>
314314
{
315315
var serverAddresses = _app.Services.GetRequiredService<IServer>().Features.Get<IServerAddressesFeature>();
316-
var address = serverAddresses?.Addresses.FirstOrDefault() ?? $"http://{_proxyConfiguration.IPAddress}:{_proxyConfiguration.ApiPort}";
316+
var serverAddress = serverAddresses?.Addresses.FirstOrDefault();
317+
var address = Uri.TryCreate(serverAddress, UriKind.Absolute, out var serverUri) ?
318+
SystemProxyAddress.ToHttpAuthority(serverUri.DnsSafeHost, serverUri.Port) :
319+
SystemProxyAddress.ToHttpAuthority(_proxyConfiguration.IPAddress, _proxyConfiguration.ApiPort);
317320
_logger.LogInformation("Dev Proxy API listening on {Address}...", address);
318321

319322
// Persist the daemon state so the parent process's readiness check,

‎DevProxy/Proxy/ConsoleHotkeyHandler.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public void PrintHotkeys()
5454

5555
public void PrintApiInstructions()
5656
{
57-
var baseUrl = $"http://{configuration.IPAddress}:{configuration.ApiPort}/proxy";
57+
var baseUrl = SystemProxyAddress.ToHttpAuthority(configuration.IPAddress, configuration.ApiPort) + "/proxy";
5858
var timestamp = DateTime.UtcNow.ToString("O", CultureInfo.InvariantCulture);
5959
console.WriteLine("");
6060
console.WriteLine($"{{\"type\":\"log\",\"level\":\"info\",\"message\":\"Issue web request: curl -X POST {baseUrl}/mockRequest\",\"category\":\"ProxyEngine\",\"timestamp\":\"{timestamp}\"}}");

‎DevProxy/config-templates/devproxyrc.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.0/rc.schema.json",
2+
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v4.0.0/rc.schema.json",
33
"plugins": [
44
],
55
"urlsToWatch": [

‎DevProxy/config-templates/devproxyrc.yaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# yaml-language-server: $schema=https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.0/rc.schema.json
1+
# yaml-language-server: $schema=https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v4.0.0/rc.schema.json
22
plugins:
33
-
44
urlsToWatch:

0 commit comments

Comments
 (0)