GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — Add configurable maximum depth in ConvertFrom-Json with `-Depth` by adamgauthier · Pull Request #8199 · PowerShell/PowerShell Conversation
|
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I think it should be:
| public int? MaxDepth { get; set; } | |
| public int MaxDepth { get; set; } = int.MaxValue; |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Don't think we have any default cmdlets with nullable input types, so I don't see any need for that. I would think that since it's a MaxDepth parameter we could either:
uint (because negative depth is insensible) with a maximum set even perhaps at something comparable to the ConvertTo-Json command which has 2 as its default -MaxDepth, or-1 and have the code paths treat that as "no maximum depth".
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the feedback, as this is my first feature contribution, I wasn't sure how to implement everything 😅
Ilya (@iSazonov) your suggestion would mean there would be no way to differentiate no maximum depth and the user wanting a maximum depth of 2147483647. I think the value representing no maximum depth should really be outside of the user input range for maximum depth (1 - 2147483647)!
Rain Sallow (/u/ta11ow) (@vexx32) I could do a uint with range of 1 - int.MaxValue and use 0 as default value representing no maximum. I could also do int with -1 as default value representing no maximum. If that's what the team prefers, I don't mind, I was just using null as a way to represent the parameter not being specified. 😄
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Yeah, you have a point there; a maximum depth of 0 is also pretty silly. However, given that the underlying json API uses int for these parameters, as Ilya (@iSazonov) pointed out, we can't safely use uint as it would allow the user to specify values that the underlying API can't handle.
I think we need some clarification on whether the json API itself has a defined specification for "no maximum depth" and what that would look like.
Mark Kraus (@markekraus) I know you worked on Invoke-RestMethod a good bit, do you have any insight to offer on the json API that might help here?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Rain Sallow (/u/ta11ow) (@vexx32) I meant I could do uint with [ValidateRange(1, int.MaxValue)], effectively not allowing user input values outside the underlying API. (but we'll have to cast the value so it might just be better to use int directly?)
Also, I was proposing 0 because the underlying API doesn't allow 0 for MaxDepth, only 1 - int.MaxValue (it throws an exception at runtime, see here).
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Oh, that's just funny at that point. If you're going to throw that early... why not just make it uint haha!
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
The underlying type is an int, so we should probably accept an int with the [ValidateRange(1, int.MaxValue)]. realistically, an JSON with a depth greater than int32.MaxValue is probably bad JSON to begin with.... A nullable type for this would be weird. accepting -1 is also weird.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
@PowerShell/powershell-committee reviewed this, the design should be that there is a |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Steve Lee (@SteveL-MSFT) with all due respect, may I ask to reconsider this decision? The
PS C:\> ConvertTo-Json (ConvertFrom-Json '{"1":{"2":{"3":{"4":{"5":1}}}}}') { "1": { "2": { "3": "@{4=}" } } }
Furthermore, I believe the current I also think putting I know it would be a breaking change to have no maximum be the new default, but is it really a common scenario that someone is relying on the default behavior failing with input of depth higher than 1024? I think handling higher depth with this new parameter is the perfect opportunity to change the default behavior to something more intuitive: the cmdlets should handle whatever is thrown at them, if the user expects the input to cause a DoS in their system (which I assume was the reason for this default max depth), then they should specify a maximum depth optionally. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
So we should discuss:
My thoughts:
/cc Mark Kraus (@markekraus) Michael Klement (@mklement0) What do you think? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
Adam Gauthier (@louistio) to be clear, the decision regarding It would also be useful if you can provide examples where the current limit of 1024 is insufficient. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Steve Lee (@SteveL-MSFT) Thank you! To be clear the naming is not a big concern to me, it's more about the bad user experience of having a default that I described later in my post. 😄 |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
@PowerShell/powershell-committee had a very bikeshed conversation about this, and we understand the parallel concepts argument with this rough visualization: Does anyone else actually care? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Two cents:
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Mark Kraus (@markekraus) Michael Klement (@mklement0) Have you any thoughts about consistency of Depth parameters? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I agree with Rob Holt (@rjmholt) |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Joey Aiello (@joeyaiello) Steve Lee (@SteveL-MSFT) Seems we can make final conclusion and continue the PR. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
In terms of naming, Regrettably, exceeding that maximum depth doesn't cause an error in In a utopian world, unencumbered by backward-compatibility concerns:
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Rob Holt (@rjmholt) Fair point about powershell being secure by default. Michael Klement (@mklement0) I agree with everything you're saying, I think you basically put into words what I was struggling to convey. I like the idea of another switch for no I would like to implement an equivalent to |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Adam Gauthier (@louistio) What would be the difference between |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
Mark Kraus (@markekraus) As mentioned above, the behavior difference resides in the cmdlet failing on input exceeding the maximum depth. Currently What I'm saying is I'd be fine with changing |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I think it would be confusing to have both Depth and Max Depth. We should have one for the depth and one to adjust the behavior of that depth. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
True, having both
(What is conceptually)
I personally then don't see a need for any other parameters - I think opting into levels beyond the fixed limit with an explicit number or even with In the absence of using
As for required changes and backward compatibility:
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
There are 2 things: 1) The maximum depth you want to convert and 2) the behavior of that conversion. They both need to be configurable, IMO and just relying on a single param for both would be a pain. There are a very large number of objects passed to Consider the Current behavior:
I would ultimately like to see it as this:
Ideally we would would want a But, keeping in mind that we could add parameters to control the behavior later, for this PR all we need is to add A bit of flavor text: A JSON object over 1024 in depth is an outlier. Other than abused/broken APIs or contrived examples, I have rarely seen a legit JSON objet that is deeper than ~30. On the flip-side, infinitely deep objects are very commonly thrown at ConvertTo-Json. (Based on my experience, YMMV.) |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
I think it is better to make both changes for Depth in the PR to get clean history and continue with rest ideas in follow PRs. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
Thanks for the analysis, Mark Kraus (@markekraus), but I still think
To put it differently: the hard-coded max. depth is then no longer a default value for If you have a "runaway" tree of infinite depth, then the hard-coded max. will save you. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
@PowerShell/powershell-committee appreciates the discussion and we still suggest that we have the single |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
-Depth
|
Mark Kraus (@markekraus) Michael Klement (@mklement0) Steve Lee (@SteveL-MSFT) Please update your review. Adam Gauthier (@louistio) Please fix StyleCop issues. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| MetadataPropertyHandling = MetadataPropertyHandling.Ignore | ||
| }; | ||
|
|
||
| if (maxDepth != null) |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
.MaxDepth == null means no limit, so it doesn't seem this check is necessary
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| @{ Depth = 2; AsHashtable = $false } | ||
| @{ Depth = 200; AsHashtable = $true } | ||
| @{ Depth = 200; AsHashtable = $false } | ||
| @{ Depth = 2000; AsHashtable = $true } |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
How long does this take to run? If longer than 2 secs, we should have them as Feature tests instead of CI.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
|
||
| It 'Fails to convert an object of depth higher than 1024 by default with AsHashtable switch set to <AsHashtable>' -TestCases $testCasesWithAndWithoutAsHashtableSwitch { | ||
| Param($AsHashtable) | ||
| $nestedJson = GenerateNestedJson -Depth:1989 |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
wouldn't 1025 be sufficient? no need to spend extra cpu here
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| @{ Depth = 2000; AsHashtable = $false } | ||
| ) | ||
|
|
||
| function GenerateNestedJson { |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
prefer New-NestedJson
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
| function Count-ObjectDepth { | ||
| Param([PSCustomObject] $InputObject) | ||
|
|
||
| for ($i=1; $i -le 100000; $i++) |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Since you have a max depth for checking here, you should probably enforce this limit on new-nestedjson. Also, I'm not sure we need to test this deep, perhaps 2048 is sufficient
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Adam Gauthier (@louistio) Have you time to continue?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Co-Authored-By: louistio <[email protected]>
|
Ilya (@iSazonov) Hey! Sorry, I wasn't aware of the colon convention 😅 I applied your suggestions through GitHub's integrated tool, but there seems to be error when running the tests without the colons! I get errors like: I'm not super familiar as to why removing colons would cause this, could you point me into the right direction? Thanks! |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Adam Gauthier (@louistio) Sorry, colons is needed for asHashtable but not for Depth. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Steve Lee (@SteveL-MSFT) Mark Kraus (@markekraus) Please update your review. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Minor cleanup requested.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Co-Authored-By: louistio <[email protected]>
|
Steve Lee (@SteveL-MSFT) Please update your review. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Adam Gauthier (@louistio) Please update the PR description and we'll merge. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Ilya (@iSazonov) description updated, I believe this still requires documentation changes, not sure if that prevents from merging. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Adam Gauthier (@louistio) Please open new Issue in PowerShell-Docs repo and add a reference to the PR description. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Ilya (@iSazonov) done! |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Adam Gauthier (@louistio) Thanks for great work! |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
…erShell#8199) Adds an optional -Depth parameter to the cmdlet which lets the user to specify a maximum depth allowed for deserialization, which will overwrite the default maximum of 1024.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
In ConvertFrom-Json, the max depth for deserialization is 1024, however, we should investigate if the current implementation can handle object of greater depth.
There was an error while loading. Please reload this page.