-
Notifications
You must be signed in to change notification settings - Fork 281
Prevent overflow for self-referencing schemas #185
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 15 commits
77586ac
728d061
16b058d
f5a56c7
6e833ff
7d3c68d
636cf08
9fc3ed3
202fbe1
1697d8a
f91e710
d88e18c
e5f64cb
029280b
2a4eeb3
f12d221
42fce80
fb31544
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,14 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT license. | ||
|
|
||
| using System; | ||
| using System.IO; | ||
| using System.Linq; | ||
| using Microsoft.OpenApi.Extensions; | ||
| using Microsoft.OpenApi.Models; | ||
| using Microsoft.OpenApi.Readers.Interface; | ||
| using Microsoft.OpenApi.Readers.Services; | ||
| using Microsoft.OpenApi.Services; | ||
| using Microsoft.OpenApi.Validations; | ||
| using SharpYaml; | ||
| using SharpYaml.Serialization; | ||
|
|
||
|
|
@@ -60,6 +61,21 @@ public OpenApiDocument Read(Stream input, out OpenApiDiagnostic diagnostic) | |
| // Parse the OpenAPI Document | ||
| var document = context.Parse(yamlDocument, diagnostic); | ||
|
|
||
| // Resolve References if requested | ||
| switch (_settings.ReferenceResolution) | ||
| { | ||
| case ReferenceResolutionSetting.ResolveRemoteReferences: | ||
| throw new ArgumentException(Properties.SRResource.CannotResolveRemoteReferencesSynchronously); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This will be supported, right? Can we just go with NotImplementedException()?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this will be handled. If you want to resolve remote references then you should call the ReadAsync method instead. The ReadAsync will also load related documents into a workspace. #Closed
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| case ReferenceResolutionSetting.ResolveLocalReferences: | ||
| var resolver = new OpenApiReferenceResolver(document); | ||
| var walker = new OpenApiWalker(resolver); | ||
| walker.Walk(document); | ||
| break; | ||
| case | ||
| ReferenceResolutionSetting.DoNotResolveReferences: | ||
|
||
| break; | ||
| } | ||
|
|
||
| // Validate the document | ||
| var errors = document.Validate(_settings.RuleSet); | ||
| foreach (var item in errors) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,16 +22,13 @@ namespace Microsoft.OpenApi.Readers | |
| public class ParsingContext | ||
| { | ||
| private readonly Stack<string> _currentLocation = new Stack<string>(); | ||
| private readonly Dictionary<string, IOpenApiReferenceable> _referenceStore = new Dictionary<string, IOpenApiReferenceable>(); | ||
| private readonly Dictionary<string, object> _tempStorage = new Dictionary<string, object>(); | ||
| private IOpenApiVersionService _versionService; | ||
|
|
||
| private readonly Dictionary<string, Stack<string>> _loopStacks = new Dictionary<string, Stack<string>>(); | ||
| internal Dictionary<string, Func<IOpenApiAny, IOpenApiExtension>> ExtensionParsers { get; set; } = new Dictionary<string, Func<IOpenApiAny, IOpenApiExtension>>(); | ||
|
|
||
| internal RootNode RootNode { get; set; } | ||
| internal List<OpenApiTag> Tags { get; private set; } = new List<OpenApiTag>(); | ||
|
|
||
|
|
||
| /// <summary> | ||
| /// Initiates the parsing process. Not thread safe and should only be called once on a parsing context | ||
| /// </summary> | ||
|
|
@@ -131,48 +128,6 @@ public string GetLocation() | |
| return "#/" + string.Join("/", _currentLocation.Reverse().ToArray()); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Gets the referenced object. | ||
| /// </summary> | ||
| public IOpenApiReferenceable GetReferencedObject( | ||
| OpenApiDiagnostic diagnostic, | ||
| ReferenceType referenceType, | ||
| string referenceString) | ||
| { | ||
| _referenceStore.TryGetValue(referenceString, out var referencedObject); | ||
|
|
||
| // If reference has already been accessed once, simply return the same reference object. | ||
| if (referencedObject != null) | ||
| { | ||
| return referencedObject; | ||
| } | ||
|
|
||
| var reference = VersionService.ConvertToOpenApiReference(referenceString, referenceType); | ||
|
|
||
| var isReferencedObjectFound = VersionService.TryLoadReference(this, reference, out referencedObject); | ||
|
|
||
| if (isReferencedObjectFound) | ||
| { | ||
| // Populate the Reference section of the object, so that the writers | ||
| // can recognize that this is referencing another object. | ||
| referencedObject.Reference = reference; | ||
| _referenceStore.Add(referenceString, referencedObject); | ||
| } | ||
| else if (referencedObject != null) | ||
| { | ||
| return referencedObject; | ||
| } | ||
| else | ||
| { | ||
| diagnostic.Errors.Add( | ||
| new OpenApiError( | ||
| GetLocation(), | ||
| $"Cannot resolve the reference {referenceString}")); | ||
| } | ||
|
|
||
| return referencedObject; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Gets the value from the temporary storage matching the given key. | ||
| /// </summary> | ||
|
|
@@ -201,5 +156,52 @@ public void StartObject(string objectName) | |
| { | ||
| _currentLocation.Push(objectName); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Maintain history of traversals to avoid stack overflows from cycles | ||
| /// </summary> | ||
| /// <param name="loopId">Any unique identifier for a stack</param> | ||
| /// <param name="key">Identifier used to </param> | ||
| /// <returns></returns> | ||
|
||
| public bool PushLoop(string loopId, string key) | ||
| { | ||
| Stack<string> stack; | ||
| if (!_loopStacks.TryGetValue(loopId, out stack)) | ||
| { | ||
| stack = new Stack<string>(); | ||
| _loopStacks.Add(loopId, stack); | ||
| } | ||
|
|
||
| if (!stack.Contains(key)) | ||
| { | ||
| stack.Push(key); | ||
| return true; | ||
| } else | ||
| { | ||
| return false; // Loop detected | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Reset loop tracking stack | ||
| /// </summary> | ||
| /// <param name="loopid"></param> | ||
| internal void ClearLoop(string loopid) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
nit, loopId #Closed |
||
| { | ||
| _loopStacks[loopid].Clear(); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Exit from the context in cycle detection | ||
| /// </summary> | ||
| /// <param name="loopid"></param> | ||
| public void PopLoop(string loopid) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
nit, loopId |
||
| { | ||
| if (_loopStacks[loopid].Count > 0) | ||
| { | ||
| _loopStacks[loopid].Pop(); | ||
| } | ||
| } | ||
|
|
||
| } | ||
| } | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
either ResolveAllReferences or ResolveLocalAndRemoteReferences #Closed