Skip to content

Commit c944a31

Browse files
committed
Defensive programming; pass cancellation token
1 parent a4933ef commit c944a31

File tree

2 files changed

+36
-13
lines changed

2 files changed

+36
-13
lines changed

src/Microsoft.OpenApi/Reader/OpenApiJsonReader.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using Microsoft.OpenApi.Validations;
1313
using System.Linq;
1414
using Microsoft.OpenApi.Interfaces;
15+
using System;
1516

1617
namespace Microsoft.OpenApi.Reader
1718
{
@@ -29,6 +30,9 @@ public class OpenApiJsonReader : IOpenApiReader
2930
public ReadResult Read(MemoryStream input,
3031
OpenApiReaderSettings settings)
3132
{
33+
if (input is null) throw new ArgumentNullException(nameof(input));
34+
if (settings is null) throw new ArgumentNullException(nameof(settings));
35+
3236
JsonNode jsonNode;
3337
var diagnostic = new OpenApiDiagnostic();
3438
settings ??= new OpenApiReaderSettings();
@@ -62,6 +66,9 @@ public ReadResult Read(JsonNode jsonNode,
6266
OpenApiReaderSettings settings,
6367
string format = null)
6468
{
69+
if (jsonNode is null) throw new ArgumentNullException(nameof(jsonNode));
70+
if (settings is null) throw new ArgumentNullException(nameof(settings));
71+
6572
var diagnostic = new OpenApiDiagnostic();
6673
var context = new ParsingContext(diagnostic)
6774
{
@@ -114,9 +121,11 @@ public async Task<ReadResult> ReadAsync(Stream input,
114121
OpenApiReaderSettings settings,
115122
CancellationToken cancellationToken = default)
116123
{
124+
if (input is null) throw new ArgumentNullException(nameof(input));
125+
if (settings is null) throw new ArgumentNullException(nameof(settings));
126+
117127
JsonNode jsonNode;
118128
var diagnostic = new OpenApiDiagnostic();
119-
settings ??= new OpenApiReaderSettings();
120129

121130
// Parse the JSON text in the stream into JsonNodes
122131
try
@@ -142,6 +151,8 @@ public T ReadFragment<T>(MemoryStream input,
142151
out OpenApiDiagnostic diagnostic,
143152
OpenApiReaderSettings settings = null) where T : IOpenApiElement
144153
{
154+
if (input is null) throw new ArgumentNullException(nameof(input));
155+
145156
JsonNode jsonNode;
146157

147158
// Parse the JSON

src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public static ReadResult Load(MemoryStream stream,
3939
string format = null,
4040
OpenApiReaderSettings settings = null)
4141
{
42+
if (stream is null) throw new ArgumentNullException(nameof(stream));
4243
settings ??= new OpenApiReaderSettings();
4344

4445
// Get the format of the stream if not provided
@@ -69,6 +70,7 @@ public static T Load<T>(Stream input,
6970
string format = null,
7071
OpenApiReaderSettings settings = null) where T : IOpenApiElement
7172
{
73+
if (input is null) throw new ArgumentNullException(nameof(input));
7274
if (input is MemoryStream memoryStream)
7375
{
7476
return Load<T>(memoryStream, version, format, out diagnostic, settings);
@@ -104,11 +106,12 @@ public static T Load<T>(MemoryStream input, OpenApiSpecVersion version, string f
104106
/// </summary>
105107
/// <param name="url">The path to the OpenAPI file</param>
106108
/// <param name="settings"> The OpenApi reader settings.</param>
109+
/// <param name="token"></param>
107110
/// <returns></returns>
108-
public static async Task<ReadResult> LoadAsync(string url, OpenApiReaderSettings settings = null)
111+
public static async Task<ReadResult> LoadAsync(string url, OpenApiReaderSettings settings = null, CancellationToken token = default)
109112
{
110-
var result = await RetrieveStreamAndFormatAsync(url);
111-
return await LoadAsync(result.Item1, result.Item2, settings).ConfigureAwait(false);
113+
var result = await RetrieveStreamAndFormatAsync(url, token).ConfigureAwait(false);
114+
return await LoadAsync(result.Item1, result.Item2, settings, token).ConfigureAwait(false);
112115
}
113116

114117
/// <summary>
@@ -118,11 +121,12 @@ public static async Task<ReadResult> LoadAsync(string url, OpenApiReaderSettings
118121
/// <param name="url">The path to the OpenAPI file</param>
119122
/// <param name="version">Version of the OpenAPI specification that the fragment conforms to.</param>
120123
/// <param name="settings">The OpenApiReader settings.</param>
124+
/// <param name="token"></param>
121125
/// <returns>Instance of newly created IOpenApiElement.</returns>
122126
/// <returns>The OpenAPI element.</returns>
123-
public static async Task<T> LoadAsync<T>(string url, OpenApiSpecVersion version, OpenApiReaderSettings settings = null) where T : IOpenApiElement
127+
public static async Task<T> LoadAsync<T>(string url, OpenApiSpecVersion version, OpenApiReaderSettings settings = null, CancellationToken token = default) where T : IOpenApiElement
124128
{
125-
var result = await RetrieveStreamAndFormatAsync(url);
129+
var result = await RetrieveStreamAndFormatAsync(url, token).ConfigureAwait(false);
126130
return Load<T>(result.Item1, version, out var _, result.Item2, settings);
127131
}
128132

@@ -136,11 +140,13 @@ public static async Task<T> LoadAsync<T>(string url, OpenApiSpecVersion version,
136140
/// <returns></returns>
137141
public static async Task<ReadResult> LoadAsync(Stream input, string format = null, OpenApiReaderSettings settings = null, CancellationToken cancellationToken = default)
138142
{
143+
if (input is null) throw new ArgumentNullException(nameof(input));
139144
settings ??= new OpenApiReaderSettings();
145+
140146
Stream preparedStream;
141147
if (format is null)
142148
{
143-
var readResult = await PrepareStreamForReadingAsync(input, format, cancellationToken);
149+
var readResult = await PrepareStreamForReadingAsync(input, format, cancellationToken).ConfigureAwait(false);
144150
preparedStream = readResult.Item1;
145151
format = readResult.Item2;
146152
}
@@ -150,7 +156,7 @@ public static async Task<ReadResult> LoadAsync(Stream input, string format = nul
150156
}
151157

152158
// Use StreamReader to process the prepared stream (buffered for YAML, direct for JSON)
153-
var result = await InternalLoadAsync(preparedStream, format, settings, cancellationToken);
159+
var result = await InternalLoadAsync(preparedStream, format, settings, cancellationToken).ConfigureAwait(false);
154160
if (!settings.LeaveStreamOpen)
155161
{
156162
input.Dispose();
@@ -170,6 +176,7 @@ public static ReadResult Parse(string input,
170176
string format = null,
171177
OpenApiReaderSettings settings = null)
172178
{
179+
if (input is null) throw new ArgumentNullException(nameof(input));
173180
format ??= InspectInputFormat(input);
174181
settings ??= new OpenApiReaderSettings();
175182

@@ -194,6 +201,7 @@ public static T Parse<T>(string input,
194201
string format = null,
195202
OpenApiReaderSettings settings = null) where T : IOpenApiElement
196203
{
204+
if (input is null) throw new ArgumentNullException(nameof(input));
197205
format ??= InspectInputFormat(input);
198206
settings ??= new OpenApiReaderSettings();
199207
var stream = new MemoryStream(Encoding.UTF8.GetBytes(input));
@@ -209,7 +217,7 @@ private static async Task<ReadResult> InternalLoadAsync(Stream input, string for
209217

210218
if (settings?.LoadExternalRefs ?? DefaultReaderSettings.LoadExternalRefs)
211219
{
212-
var diagnosticExternalRefs = await LoadExternalRefsAsync(readResult.Document, cancellationToken, settings, format);
220+
var diagnosticExternalRefs = await LoadExternalRefsAsync(readResult.Document, settings, format, cancellationToken).ConfigureAwait(false);
213221
// Merge diagnostics of external reference
214222
if (diagnosticExternalRefs != null)
215223
{
@@ -221,7 +229,7 @@ private static async Task<ReadResult> InternalLoadAsync(Stream input, string for
221229
return readResult;
222230
}
223231

224-
private static async Task<OpenApiDiagnostic> LoadExternalRefsAsync(OpenApiDocument document, CancellationToken cancellationToken, OpenApiReaderSettings settings, string format = null)
232+
private static async Task<OpenApiDiagnostic> LoadExternalRefsAsync(OpenApiDocument document, OpenApiReaderSettings settings, string format = null, CancellationToken token = default)
225233
{
226234
// Create workspace for all documents to live in.
227235
var baseUrl = settings.BaseUrl ?? new Uri(OpenApiConstants.BaseRegistryUri);
@@ -230,7 +238,7 @@ private static async Task<OpenApiDiagnostic> LoadExternalRefsAsync(OpenApiDocume
230238
// Load this root document into the workspace
231239
var streamLoader = new DefaultStreamLoader(settings.BaseUrl);
232240
var workspaceLoader = new OpenApiWorkspaceLoader(openApiWorkSpace, settings.CustomExternalLoader ?? streamLoader, settings);
233-
return await workspaceLoader.LoadAsync(new OpenApiReference() { ExternalResource = "/" }, document, format ?? OpenApiConstants.Json, null, cancellationToken).ConfigureAwait(false);
241+
return await workspaceLoader.LoadAsync(new OpenApiReference() { ExternalResource = "/" }, document, format ?? OpenApiConstants.Json, null, token).ConfigureAwait(false);
234242
}
235243

236244
private static ReadResult InternalLoad(MemoryStream input, string format, OpenApiReaderSettings settings)
@@ -246,7 +254,7 @@ private static ReadResult InternalLoad(MemoryStream input, string format, OpenAp
246254
return readResult;
247255
}
248256

249-
private static async Task<(Stream, string)> RetrieveStreamAndFormatAsync(string url)
257+
private static async Task<(Stream, string)> RetrieveStreamAndFormatAsync(string url, CancellationToken token = default)
250258
{
251259
if (!string.IsNullOrEmpty(url))
252260
{
@@ -256,11 +264,15 @@ private static ReadResult InternalLoad(MemoryStream input, string format, OpenAp
256264
if (url.StartsWith("http", StringComparison.OrdinalIgnoreCase)
257265
|| url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
258266
{
259-
var response = await _httpClient.GetAsync(url);
267+
var response = await _httpClient.GetAsync(url, token).ConfigureAwait(false);
260268
var mediaType = response.Content.Headers.ContentType.MediaType;
261269
var contentType = mediaType.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)[0];
262270
format = contentType.Split('/').LastOrDefault();
271+
#if NETSTANDARD2_0
263272
stream = await response.Content.ReadAsStreamAsync();
273+
#else
274+
stream = await response.Content.ReadAsStreamAsync(token).ConfigureAwait(false);;
275+
#endif
264276
return (stream, format);
265277
}
266278
else

0 commit comments

Comments
 (0)