-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Fix missing collection type in paginated requests #53725
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
Fix missing collection type in paginated requests #53725
Conversation
c4da152 to
55bc091
Compare
icewind1991
left a comment
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.
using serialize/deserialize is a bad idea for a number of reasons.
It would be much better to just ensure that all properties are json-serializable
55bc091 to
06b0b35
Compare
1610dbf to
e29211c
Compare
| } elseif (is_array($value)) { | ||
| $this->decomposeArray($value); | ||
| } elseif (is_callable($value)) { | ||
| $value($this); |
Check failure
Code scanning / Psalm
TaintedCallable Error
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.
Note to reviewers: could you please have a look at this and verify my understanding that this is a false alert is incorrect?
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.
This is scary, do you really need to support callables in there? What is the source of the data, can it not be set by the user?
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.
This would be set by a sabre plugin, not the user.
We can probably get away with just not allowing this though.
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.
I'll see if this can be removed, but this is already part of SabreDAV's serializer, so I don't think we are introducing anything new here.
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.
@icewind1991 it's gone, now an InvalidArgumentException is thrown instead. I can't guarantee though that this won't ever happen 🤔 is there any way to test this in a more real-world scenario?
come-nc
left a comment
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.
This feels overengineered to me, writing a custom serializer is scary.
But I’m not sure I understand the whole context.
I had a solution with serialize/deserialize but it would have acted only on the properties that we know break and introduced issues due to serializing/deserializing objects into the cache, plus the possible security issues it could've introduced. With the custom serializer any property will be made serializable using the property of the Writer that it can serialize arrays with a certain structure. I agree that it was a lot of work for a fix of an issue that seems simple, but I couldn't come up with a fourth solution that addressed as many concerns 👀 I also considered the option of posting a PR for SabreDAV to make properties On the positive side, I tried to add a couple tests to make sure that if anything changes from SabreDAV's side, tests will fail. |
provokateurin
left a comment
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.
Didn't review the entire thing, but I have to agree that this is really overengineered. I would rather like to find a way to force developers to make their props JsonSerializable, as this is just simpler for everyone.
| } | ||
|
|
||
| foreach ($value as &$property) { | ||
| if (is_object($property)) { |
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.
| if (is_object($property)) { | |
| if (!is_array($property)) { |
Maybe I don't understand enough of the context, but does this make more sense?
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.
No those are the values of the actual properties. So $property would be 'files/admin' for href and an instance of GetLastModified for the last-modified property.
Yay, now we're three 😄 Here's what I tried or considered, in conjunction with Robin in some parts:
Regarding the fact that adding |
|
So, the point is to cache sabre answer when we have a paginated request to be able to return other pages later, right? |
It is probably possible to just render the "pages" and store those in cache as single items, provided huge strings are not a problem to store (not sure TBH), but that requires the count of items per page to be stable and due to the way the pagination is currently implemented, that is not guaranteed. If the pagination parameters were stable, that would've been a viable option. Since the pagination has been out in the public for a while, I'm not sure how acceptable it would be to freeze the pagination parameters after the first request and then store XML directly and return it in subsequent pagination calls. |
The pagination plugin for DAV stores file properties in a cache using json_encode. This works only if all proprierties are serializable, but the properties represented by ResourceType and GetLastModified are not. Moreover, apps can add other properties and those also needs to be serializable. Since the json-serializability is not guaranteed, this commit introduces an ArrayWriter class that can be passed to xmlSerialize to create a serializable array structure that is usable by \Sabre\Xml\Writer during the actual XML serialization process. Signed-off-by: Salvatore Martire <[email protected]>
Signed-off-by: Salvatore Martire <[email protected]>
Signed-off-by: Salvatore Martire <[email protected]>
Signed-off-by: Salvatore Martire <[email protected]>
Signed-off-by: Salvatore Martire <[email protected]>
Signed-off-by: Salvatore Martire <[email protected]>
Signed-off-by: Salvatore Martire <[email protected]>
Signed-off-by: Salvatore Martire <[email protected]>
Signed-off-by: Salvatore Martire <[email protected]>
Signed-off-by: Salvatore Martire <[email protected]>
47e84fe to
eed3248
Compare
|
closing this PR in favor of #56035 |
Summary
Problem
When using the custom pagination some attributes are missing or have invalid values.
json_encodeandjson_decodeare used to store and retrieve entries to/from the cache. This involuntarily removes classes that are not extendingJsonSerializableor anyways produce wrong XML output.Solution
To prevent this from happening in the future, since we cannot get the guarantee that properties are json-serializable, we must make sure that they are ourselves. This is done by providing a custom implementation of
Sabre\XML\Writerwhich produces an array with a structure that can be re-serialised by aSabre\XML\Writerinstance.Once this writer is used, cached file properties are then rendered correctly:
Checklist