Skip to content

Commit 50ddca2

Browse files
authored
Merge pull request #2124 from microsoft/fix/loading-exception
fix: support non-standard MIME type in response header
2 parents 878dd08 + 711b3d1 commit 50ddca2

File tree

4 files changed

+45
-12
lines changed

4 files changed

+45
-12
lines changed

src/Microsoft.OpenApi.Hidi/OpenApiService.cs

+4-5
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ private static async Task<OpenApiDocument> GetOpenApiAsync(HidiOptions options,
254254
else if (!string.IsNullOrEmpty(options.OpenApi))
255255
{
256256
stream = await GetStreamAsync(options.OpenApi, logger, cancellationToken).ConfigureAwait(false);
257-
var result = await ParseOpenApiAsync(options.OpenApi, format, options.InlineExternal, logger, stream, cancellationToken).ConfigureAwait(false);
257+
var result = await ParseOpenApiAsync(options.OpenApi, options.InlineExternal, logger, stream, cancellationToken).ConfigureAwait(false);
258258
document = result.Document;
259259
}
260260
else throw new InvalidOperationException("No input file path or URL provided");
@@ -351,8 +351,7 @@ private static MemoryStream ApplyFilterToCsdl(Stream csdlStream, string entitySe
351351
try
352352
{
353353
using var stream = await GetStreamAsync(openApi, logger, cancellationToken).ConfigureAwait(false);
354-
var openApiFormat = !string.IsNullOrEmpty(openApi) ? GetOpenApiFormat(openApi, logger) : OpenApiFormat.Yaml;
355-
result = await ParseOpenApiAsync(openApi, openApiFormat.GetDisplayName(),false, logger, stream, cancellationToken).ConfigureAwait(false);
354+
result = await ParseOpenApiAsync(openApi, false, logger, stream, cancellationToken).ConfigureAwait(false);
356355

357356
using (logger.BeginScope("Calculating statistics"))
358357
{
@@ -380,7 +379,7 @@ private static MemoryStream ApplyFilterToCsdl(Stream csdlStream, string entitySe
380379
return result.Diagnostic.Errors.Count == 0;
381380
}
382381

383-
private static async Task<ReadResult> ParseOpenApiAsync(string openApiFile, string format, bool inlineExternal, ILogger logger, Stream stream, CancellationToken cancellationToken = default)
382+
private static async Task<ReadResult> ParseOpenApiAsync(string openApiFile, bool inlineExternal, ILogger logger, Stream stream, CancellationToken cancellationToken = default)
384383
{
385384
ReadResult result;
386385
var stopwatch = Stopwatch.StartNew();
@@ -396,7 +395,7 @@ private static async Task<ReadResult> ParseOpenApiAsync(string openApiFile, stri
396395
new Uri("file://" + new FileInfo(openApiFile).DirectoryName + Path.DirectorySeparatorChar)
397396
};
398397

399-
result = await OpenApiDocument.LoadAsync(stream, format, settings, cancellationToken).ConfigureAwait(false);
398+
result = await OpenApiDocument.LoadAsync(stream, settings: settings, cancellationToken: cancellationToken).ConfigureAwait(false);
400399

401400
logger.LogTrace("{Timestamp}ms: Completed parsing.", stopwatch.ElapsedMilliseconds);
402401

src/Microsoft.OpenApi/Models/OpenApiOperation.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ public void SerializeAsV3(IOpenApiWriter writer)
160160
/// </summary>
161161
private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, Action<IOpenApiWriter, IOpenApiSerializable> callback)
162162
{
163-
Utils.CheckArgumentNull(writer);;
163+
Utils.CheckArgumentNull(writer);
164164

165165
writer.WriteStartObject();
166166

src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs

+31-6
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,11 @@ public static ReadResult Load(MemoryStream stream,
3939
string format = null,
4040
OpenApiReaderSettings settings = null)
4141
{
42+
#if NET6_0_OR_GREATER
43+
ArgumentNullException.ThrowIfNull(stream);
44+
#else
4245
if (stream is null) throw new ArgumentNullException(nameof(stream));
46+
#endif
4347
settings ??= new OpenApiReaderSettings();
4448

4549
// Get the format of the stream if not provided
@@ -112,7 +116,11 @@ public static async Task<T> LoadAsync<T>(string url, OpenApiSpecVersion version,
112116
/// <returns></returns>
113117
public static async Task<ReadResult> LoadAsync(Stream input, string format = null, OpenApiReaderSettings settings = null, CancellationToken cancellationToken = default)
114118
{
119+
#if NET6_0_OR_GREATER
120+
ArgumentNullException.ThrowIfNull(input);
121+
#else
115122
if (input is null) throw new ArgumentNullException(nameof(input));
123+
#endif
116124
settings ??= new OpenApiReaderSettings();
117125

118126
Stream preparedStream;
@@ -160,7 +168,11 @@ public static async Task<T> LoadAsync<T>(Stream input,
160168
CancellationToken token = default) where T : IOpenApiElement
161169
{
162170
Utils.CheckArgumentNull(openApiDocument);
171+
#if NET6_0_OR_GREATER
172+
ArgumentNullException.ThrowIfNull(input);
173+
#else
163174
if (input is null) throw new ArgumentNullException(nameof(input));
175+
#endif
164176
if (input is MemoryStream memoryStream)
165177
{
166178
return Load<T>(memoryStream, version, format, openApiDocument, out var _, settings);
@@ -185,7 +197,11 @@ public static ReadResult Parse(string input,
185197
string format = null,
186198
OpenApiReaderSettings settings = null)
187199
{
188-
if (input is null) throw new ArgumentNullException(nameof(input));
200+
#if NET6_0_OR_GREATER
201+
ArgumentException.ThrowIfNullOrEmpty(input);
202+
#else
203+
if (string.IsNullOrEmpty(input)) throw new ArgumentNullException(nameof(input));
204+
#endif
189205
format ??= InspectInputFormat(input);
190206
settings ??= new OpenApiReaderSettings();
191207

@@ -212,7 +228,11 @@ public static T Parse<T>(string input,
212228
string format = null,
213229
OpenApiReaderSettings settings = null) where T : IOpenApiElement
214230
{
215-
if (input is null) throw new ArgumentNullException(nameof(input));
231+
#if NET6_0_OR_GREATER
232+
ArgumentException.ThrowIfNullOrEmpty(input);
233+
#else
234+
if (string.IsNullOrEmpty(input)) throw new ArgumentNullException(nameof(input));
235+
#endif
216236
format ??= InspectInputFormat(input);
217237
settings ??= new OpenApiReaderSettings();
218238
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(input));
@@ -278,11 +298,12 @@ private static ReadResult InternalLoad(MemoryStream input, string format, OpenAp
278298
var response = await _httpClient.GetAsync(url, token).ConfigureAwait(false);
279299
var mediaType = response.Content.Headers.ContentType.MediaType;
280300
var contentType = mediaType.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)[0];
281-
format = contentType.Split('/').LastOrDefault();
301+
format = contentType.Split('/').Last().Split('+').Last().Split('-').Last();
302+
// for non-standard MIME types e.g. text/x-yaml used in older libs or apps
282303
#if NETSTANDARD2_0
283304
stream = await response.Content.ReadAsStreamAsync();
284305
#else
285-
stream = await response.Content.ReadAsStreamAsync(token).ConfigureAwait(false);;
306+
stream = await response.Content.ReadAsStreamAsync(token).ConfigureAwait(false);
286307
#endif
287308
return (stream, format);
288309
}
@@ -321,8 +342,12 @@ private static string InspectInputFormat(string input)
321342

322343
private static string InspectStreamFormat(Stream stream)
323344
{
324-
if (stream == null) throw new ArgumentNullException(nameof(stream));
325-
345+
#if NET6_0_OR_GREATER
346+
ArgumentNullException.ThrowIfNull(stream);
347+
#else
348+
if (stream is null) throw new ArgumentNullException(nameof(stream));
349+
#endif
350+
326351
long initialPosition = stream.Position;
327352
int firstByte = stream.ReadByte();
328353

test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs

+9
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ namespace Microsoft.OpenApi.Readers.Tests.V3Tests
2626
public class OpenApiDocumentTests
2727
{
2828
private const string SampleFolderPath = "V3Tests/Samples/OpenApiDocument/";
29+
private const string codacyApi = "https://api.codacy.com/api/api-docs/swagger.yaml";
2930

3031
public OpenApiDocumentTests()
3132
{
@@ -1362,5 +1363,13 @@ public async Task ParseDocumentWithExampleReferencesPasses()
13621363
var result = await OpenApiDocument.LoadAsync(Path.Combine(SampleFolderPath, "docWithExampleReferences.yaml"));
13631364
Assert.Empty(result.Diagnostic.Errors);
13641365
}
1366+
1367+
[Fact]
1368+
public async Task ParseDocumentWithNonStandardMIMETypePasses()
1369+
{
1370+
// Act & Assert: Ensure NotSupportedException is not thrown for non-standard MIME type: text/x-yaml
1371+
var result = await OpenApiDocument.LoadAsync(codacyApi);
1372+
Assert.NotNull(result.Document);
1373+
}
13651374
}
13661375
}

0 commit comments

Comments
 (0)