diff --git a/.github/workflows/release-please-gha.yml b/.github/workflows/release-please-gha.yml
index 173b15cbb..5750600d8 100644
--- a/.github/workflows/release-please-gha.yml
+++ b/.github/workflows/release-please-gha.yml
@@ -36,3 +36,4 @@ jobs:
token: ${{ steps.app-token.outputs.token }}
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
+ target-branch: ${{ github.ref_name }}
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index a3976f1a8..8a45bd5dd 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "2.3.3"
+ ".": "2.3.4"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5ca0751e8..361168645 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,14 @@
# Changelog
+## [2.3.4](https://github.com/microsoft/OpenAPI.NET/compare/v2.3.3...v2.3.4) (2025-10-06)
+
+
+### Bug Fixes
+
+* Improve server creation and URL handling logic to maintain port ([3e6ee80](https://github.com/microsoft/OpenAPI.NET/commit/3e6ee80491ab32d810d40f29761b8eb8e4c4ce23))
+* missing deserialization for header content property in 3.1 and 3.0 ([717f154](https://github.com/microsoft/OpenAPI.NET/commit/717f1547bf94c3e9f76078d9a3b93ce684e17306))
+* missing deserialization for header content property in 3.1 and 3.0 ([0fdfae1](https://github.com/microsoft/OpenAPI.NET/commit/0fdfae1b0bf4d371af8ad3bfa6ad4df3da8d545b))
+
## [2.3.3](https://github.com/microsoft/OpenAPI.NET/compare/v2.3.2...v2.3.3) (2025-10-02)
diff --git a/Directory.Build.props b/Directory.Build.props
index d61db6d94..c8f5a4612 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -12,7 +12,7 @@
https://github.com/Microsoft/OpenAPI.NET
© Microsoft Corporation. All rights reserved.
OpenAPI .NET
- 2.3.3
+ 2.3.4
diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs
index 3de0b24a0..140ebbe23 100644
--- a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs
+++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs
@@ -124,14 +124,14 @@ private static void MakeServers(IList servers, ParsingContext con
basePath = "/";
}
- // If nothing is provided, don't create a server
- if (host == null && basePath == null && schemes == null)
+ // If nothing is provided and there's no defaultUrl, don't create a server
+ if (string.IsNullOrEmpty(host) && string.IsNullOrEmpty(basePath) && (schemes == null || schemes.Count == 0) && defaultUrl == null)
{
return;
}
//Validate host
- if (host != null && !IsHostValid(host))
+ if (!string.IsNullOrEmpty(host) && !IsHostValid(host!))
{
rootNode.Context.Diagnostic.Errors.Add(new(rootNode.Context.GetLocation(), "Invalid host"));
return;
@@ -140,7 +140,7 @@ private static void MakeServers(IList servers, ParsingContext con
// Fill in missing information based on the defaultUrl
if (defaultUrl != null)
{
- host = host ?? defaultUrl.GetComponents(UriComponents.NormalizedHost, UriFormat.SafeUnescaped);
+ host = host ?? defaultUrl.GetComponents(UriComponents.Host | UriComponents.Port, UriFormat.SafeUnescaped);
basePath = basePath ?? defaultUrl.GetComponents(UriComponents.Path, UriFormat.SafeUnescaped);
schemes = schemes ?? [defaultUrl.GetComponents(UriComponents.Scheme, UriFormat.SafeUnescaped)];
}
@@ -150,7 +150,7 @@ private static void MakeServers(IList servers, ParsingContext con
}
// Create the Server objects
- if (schemes is {Count: > 0})
+ if (schemes is { Count: > 0 })
{
foreach (var scheme in schemes)
{
@@ -202,8 +202,8 @@ private static string BuildUrl(string? scheme, string? host, string? basePath)
if (pieces is not null)
{
host = pieces[0];
- port = int.Parse(pieces[pieces.Count() -1], CultureInfo.InvariantCulture);
- }
+ port = int.Parse(pieces[pieces.Count() - 1], CultureInfo.InvariantCulture);
+ }
}
var uriBuilder = new UriBuilder
@@ -218,6 +218,13 @@ private static string BuildUrl(string? scheme, string? host, string? basePath)
uriBuilder.Port = port.Value;
}
+ // Remove default ports to clean up the URL
+ if (("https".Equals(uriBuilder.Scheme, StringComparison.OrdinalIgnoreCase) && uriBuilder.Port == 443) ||
+ ("http".Equals(uriBuilder.Scheme, StringComparison.OrdinalIgnoreCase) && uriBuilder.Port == 80))
+ {
+ uriBuilder.Port = -1; // Setting to -1 removes the port from the URL
+ }
+
return uriBuilder.ToString();
}
diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiServerTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiServerTests.cs
index f5f6078a2..c2a8b7115 100644
--- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiServerTests.cs
+++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiServerTests.cs
@@ -318,5 +318,177 @@ public void InvalidHostShouldYieldError()
Format = OpenApiConstants.Yaml
}, result.Diagnostic);
}
+
+ [Fact]
+ public void BaseUrlWithPortShouldPreservePort()
+ {
+ var input =
+ """
+ swagger: 2.0
+ info:
+ title: test
+ version: 1.0.0
+ paths: {}
+ """;
+ var settings = new OpenApiReaderSettings
+ {
+ BaseUrl = new("http://demo.testfire.net:8080")
+ };
+ settings.AddYamlReader();
+
+ var result = OpenApiDocument.Parse(input, "yaml", settings);
+
+ var server = result.Document.Servers.First();
+ Assert.Single(result.Document.Servers);
+ Assert.Equal("http://demo.testfire.net:8080", server.Url);
+ }
+
+ [Fact]
+ public void BaseUrlWithPortAndPathShouldPreservePort()
+ {
+ var input =
+ """
+ swagger: 2.0
+ info:
+ title: test
+ version: 1.0.0
+ paths: {}
+ """;
+ var settings = new OpenApiReaderSettings
+ {
+ BaseUrl = new("http://demo.testfire.net:8080/swagger/properties.json")
+ };
+ settings.AddYamlReader();
+
+ var result = OpenApiDocument.Parse(input, "yaml", settings);
+
+ var server = result.Document.Servers.First();
+ Assert.Single(result.Document.Servers);
+ Assert.Equal("http://demo.testfire.net:8080/swagger/properties.json", server.Url);
+ }
+
+ [Fact]
+ public void BaseUrlWithNonStandardPortShouldPreservePort()
+ {
+ var input =
+ """
+ swagger: 2.0
+ info:
+ title: test
+ version: 1.0.0
+ paths: {}
+ """;
+ var settings = new OpenApiReaderSettings
+ {
+ BaseUrl = new("https://api.example.com:9443/v1/openapi.yaml")
+ };
+ settings.AddYamlReader();
+
+ var result = OpenApiDocument.Parse(input, "yaml", settings);
+
+ var server = result.Document.Servers.First();
+ Assert.Single(result.Document.Servers);
+ Assert.Equal("https://api.example.com:9443/v1/openapi.yaml", server.Url);
+ }
+
+ [Fact]
+ public void BaseUrlWithStandardHttpsPortShouldRemovePort()
+ {
+ var input =
+ """
+ swagger: 2.0
+ info:
+ title: test
+ version: 1.0.0
+ paths: {}
+ """;
+ var settings = new OpenApiReaderSettings
+ {
+ BaseUrl = new("https://foo.bar:443/api")
+ };
+ settings.AddYamlReader();
+
+ var result = OpenApiDocument.Parse(input, "yaml", settings);
+
+ var server = result.Document.Servers.First();
+ Assert.Single(result.Document.Servers);
+ Assert.Equal("https://foo.bar/api", server.Url);
+ }
+
+ [Fact]
+ public void BaseUrlWithStandardHttpPortShouldRemovePort()
+ {
+ var input =
+ """
+ swagger: 2.0
+ info:
+ title: test
+ version: 1.0.0
+ paths: {}
+ """;
+ var settings = new OpenApiReaderSettings
+ {
+ BaseUrl = new("http://foo.bar:80/api")
+ };
+ settings.AddYamlReader();
+
+ var result = OpenApiDocument.Parse(input, "yaml", settings);
+
+ var server = result.Document.Servers.First();
+ Assert.Single(result.Document.Servers);
+ Assert.Equal("http://foo.bar/api", server.Url);
+ }
+
+ [Fact]
+ public void HostWithStandardHttpsPortShouldRemovePort()
+ {
+ var input =
+ """
+ swagger: 2.0
+ info:
+ title: test
+ version: 1.0.0
+ host: foo.bar:443
+ schemes:
+ - https
+ paths: {}
+ """;
+ var settings = new OpenApiReaderSettings
+ {
+ };
+ settings.AddYamlReader();
+
+ var result = OpenApiDocument.Parse(input, "yaml", settings);
+
+ var server = result.Document.Servers.First();
+ Assert.Single(result.Document.Servers);
+ Assert.Equal("https://foo.bar", server.Url);
+ }
+
+ [Fact]
+ public void HostWithStandardHttpPortShouldRemovePort()
+ {
+ var input =
+ """
+ swagger: 2.0
+ info:
+ title: test
+ version: 1.0.0
+ host: foo.bar:80
+ schemes:
+ - http
+ paths: {}
+ """;
+ var settings = new OpenApiReaderSettings
+ {
+ };
+ settings.AddYamlReader();
+
+ var result = OpenApiDocument.Parse(input, "yaml", settings);
+
+ var server = result.Document.Servers.First();
+ Assert.Single(result.Document.Servers);
+ Assert.Equal("http://foo.bar", server.Url);
+ }
}
}