Skip to content

Commit f61cbe1

Browse files
authored
Merge pull request #2150 from microsoft/fix/load-external-references
fix/load external references
2 parents 20aacc1 + 3afb8db commit f61cbe1

File tree

6 files changed

+35
-28
lines changed

6 files changed

+35
-28
lines changed

src/Microsoft.OpenApi/Interfaces/IStreamLoader.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.IO;
6+
using System.Threading;
67
using System.Threading.Tasks;
78
using Microsoft.OpenApi.Models;
89

@@ -17,7 +18,8 @@ public interface IStreamLoader
1718
/// Use Uri to locate data and convert into an input object.
1819
/// </summary>
1920
/// <param name="uri">Identifier of some source of an OpenAPI Description</param>
21+
/// <param name="cancellationToken">The cancellation token.</param>
2022
/// <returns>A data object that can be processed by a reader to generate an <see cref="OpenApiDocument"/></returns>
21-
Task<Stream> LoadAsync(Uri uri);
23+
Task<Stream> LoadAsync(Uri uri, CancellationToken cancellationToken = default);
2224
}
2325
}

src/Microsoft.OpenApi/Reader/Services/DefaultStreamLoader.cs

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using System;
55
using System.IO;
66
using System.Net.Http;
7+
using System.Runtime.InteropServices;
8+
using System.Threading;
79
using System.Threading.Tasks;
810
using Microsoft.OpenApi.Interfaces;
911
using Microsoft.OpenApi.Models;
@@ -27,28 +29,29 @@ public DefaultStreamLoader(Uri baseUrl)
2729
this.baseUrl = baseUrl;
2830
}
2931

30-
/// <summary>
31-
/// Use Uri to locate data and convert into an input object.
32-
/// </summary>
33-
/// <param name="uri">Identifier of some source of an OpenAPI Description</param>
34-
/// <returns>A data object that can be processed by a reader to generate an <see cref="OpenApiDocument"/></returns>
35-
/// <exception cref="ArgumentException"></exception>
36-
public async Task<Stream> LoadAsync(Uri uri)
32+
/// <inheritdoc/>
33+
public async Task<Stream> LoadAsync(Uri uri, CancellationToken cancellationToken = default)
3734
{
38-
Uri absoluteUri;
39-
absoluteUri = baseUrl.AbsoluteUri.Equals(OpenApiConstants.BaseRegistryUri) ? new Uri(Directory.GetCurrentDirectory() + uri)
40-
: new Uri(baseUrl, uri);
35+
var absoluteUri = (baseUrl.AbsoluteUri.Equals(OpenApiConstants.BaseRegistryUri), baseUrl.IsAbsoluteUri, uri.IsAbsoluteUri) switch
36+
{
37+
(true, _, _) => new Uri(Path.Combine(Directory.GetCurrentDirectory(), uri.ToString())),
38+
// this overcomes a URI concatenation issue for local paths on linux OSes
39+
(_, true, false) when baseUrl.Scheme.Equals("file", StringComparison.OrdinalIgnoreCase) && !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) =>
40+
new Uri(Path.Combine(baseUrl.AbsoluteUri, uri.ToString())),
41+
(_, _, _) => new Uri(baseUrl, uri),
42+
};
4143

42-
switch (absoluteUri.Scheme)
44+
return absoluteUri.Scheme switch
4345
{
44-
case "file":
45-
return File.OpenRead(absoluteUri.AbsolutePath);
46-
case "http":
47-
case "https":
48-
return await _httpClient.GetStreamAsync(absoluteUri);
49-
default:
50-
throw new ArgumentException("Unsupported scheme");
51-
}
46+
"file" => File.OpenRead(absoluteUri.AbsolutePath),
47+
"http" or "https" =>
48+
#if NET5_0_OR_GREATER
49+
await _httpClient.GetStreamAsync(absoluteUri, cancellationToken).ConfigureAwait(false),
50+
#else
51+
await _httpClient.GetStreamAsync(absoluteUri).ConfigureAwait(false),
52+
#endif
53+
_ => throw new ArgumentException("Unsupported scheme"),
54+
};
5255
}
5356
}
5457
}

src/Microsoft.OpenApi/Reader/Services/OpenApiWorkspaceLoader.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,16 @@ internal async Task<OpenApiDiagnostic> LoadAsync(OpenApiReference reference,
4545
// If not already in workspace, load it and process references
4646
if (!_workspace.Contains(item.ExternalResource))
4747
{
48-
var input = await _loader.LoadAsync(new(item.ExternalResource, UriKind.RelativeOrAbsolute));
49-
var result = await OpenApiDocument.LoadAsync(input, format, _readerSettings, cancellationToken);
48+
var input = await _loader.LoadAsync(new(item.ExternalResource, UriKind.RelativeOrAbsolute), cancellationToken).ConfigureAwait(false);
49+
var result = await OpenApiDocument.LoadAsync(input, format, _readerSettings, cancellationToken).ConfigureAwait(false);
5050
// Merge diagnostics
5151
if (result.Diagnostic != null)
5252
{
5353
diagnostic.AppendDiagnostic(result.Diagnostic, item.ExternalResource);
5454
}
5555
if (result.Document != null)
5656
{
57-
var loadDiagnostic = await LoadAsync(item, result.Document, format, diagnostic, cancellationToken);
57+
var loadDiagnostic = await LoadAsync(item, result.Document, format, diagnostic, cancellationToken).ConfigureAwait(false);
5858
diagnostic = loadDiagnostic;
5959
}
6060
}

test/Microsoft.OpenApi.Readers.Tests/OpenApiReaderTests/OpenApiDiagnosticTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT license.
33

4+
using System.Threading;
45
using System.Threading.Tasks;
56
using System;
67
using Microsoft.OpenApi.Models;
@@ -64,7 +65,7 @@ public Stream Load(Uri uri)
6465
return null;
6566
}
6667

67-
public Task<Stream> LoadAsync(Uri uri)
68+
public Task<Stream> LoadAsync(Uri uri, CancellationToken cancellationToken = default)
6869
{
6970
var path = new Uri(new("http://example.org/OpenApiReaderTests/Samples/OpenApiDiagnosticReportMerged/"), uri).AbsolutePath;
7071
path = path[1..]; // remove leading slash

test/Microsoft.OpenApi.Readers.Tests/OpenApiWorkspaceTests/OpenApiWorkspaceStreamTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.IO;
3+
using System.Threading;
34
using System.Threading.Tasks;
45
using Microsoft.OpenApi.Interfaces;
56
using Microsoft.OpenApi.Models;
@@ -80,7 +81,7 @@ public Stream Load(Uri uri)
8081
return null;
8182
}
8283

83-
public Task<Stream> LoadAsync(Uri uri)
84+
public Task<Stream> LoadAsync(Uri uri, CancellationToken cancellationToken = default)
8485
{
8586
return Task.FromResult<Stream>(null);
8687
}
@@ -93,7 +94,7 @@ public Stream Load(Uri uri)
9394
return null;
9495
}
9596

96-
public Task<Stream> LoadAsync(Uri uri)
97+
public Task<Stream> LoadAsync(Uri uri, CancellationToken cancellationToken = default)
9798
{
9899
var path = new Uri(new("http://example.org/V3Tests/Samples/OpenApiWorkspace/"), uri).AbsolutePath;
99100
path = path[1..]; // remove leading slash

test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ namespace Microsoft.OpenApi.Interfaces
246246
}
247247
public interface IStreamLoader
248248
{
249-
System.Threading.Tasks.Task<System.IO.Stream> LoadAsync(System.Uri uri);
249+
System.Threading.Tasks.Task<System.IO.Stream> LoadAsync(System.Uri uri, System.Threading.CancellationToken cancellationToken = default);
250250
}
251251
}
252252
namespace Microsoft.OpenApi
@@ -1554,7 +1554,7 @@ namespace Microsoft.OpenApi.Reader.Services
15541554
public class DefaultStreamLoader : Microsoft.OpenApi.Interfaces.IStreamLoader
15551555
{
15561556
public DefaultStreamLoader(System.Uri baseUrl) { }
1557-
public System.Threading.Tasks.Task<System.IO.Stream> LoadAsync(System.Uri uri) { }
1557+
public System.Threading.Tasks.Task<System.IO.Stream> LoadAsync(System.Uri uri, System.Threading.CancellationToken cancellationToken = default) { }
15581558
}
15591559
}
15601560
namespace Microsoft.OpenApi.Services

0 commit comments

Comments
 (0)