Skip to content
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

[full-ci] Enable streaming for propfind #38583

Merged
merged 1 commit into from
Oct 13, 2021

Conversation

DeepDiver1975
Copy link
Member

@DeepDiver1975 DeepDiver1975 commented Mar 25, 2021

Description

Propfind requests will now be streamed to reduce memory usage with large responses.
Additionally, the new config dav.propfind.depth_infinity has been added to tell clients whether depth=infinity is allowed for propfind requests. It defaults to true.

#36336 reloaded
Fixes #14531

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Database schema changes (next release will require increase of minor version instead of patch)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Technical debt
  • Tests only (no source changes)

Checklist:

Copy link

@michaelstingl michaelstingl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add capability for the clients, so they don't meltdown servers without this improvement.

@michaelstingl
Copy link

michaelstingl commented Aug 2, 2021

@DeepDiver1975 @hodyroff what's next? Can be released in next iOS version, but there's no capability yet. When can this be released?

@DeepDiver1975
Copy link
Member Author

DeepDiver1975 commented Aug 2, 2021

When can this be released?

Once these things are taken care of:

  • capability
  • add dedicated acceptance tests for depth infinity (especially exceptional scenarios)
  • fix any issues which arise (basically fix all acceptance tests when streaming is enabled on all requests/responses)
  • enable streaming only if depth: infinity is used (risk minimization)

total effort: ~2 weeks

@JammingBen JammingBen force-pushed the feature/sabre-with-streaming-propfind-reloaded branch from 5681f1a to 8e4c4a0 Compare October 6, 2021 09:12
@JammingBen JammingBen changed the title Enable streaming for propfind [full-ci] Enable streaming for propfind Oct 6, 2021
@ownclouders
Copy link
Contributor

💥 Acceptance tests pipeline apiProxySmoke-8-5-mariadb10.2-php7.4 failed. The build has been cancelled.

https://drone.owncloud.com/owncloud/core/32901/172/1

@JammingBen
Copy link
Contributor

@DeepDiver1975

Regarding those invalid XML responses:

<?xml version="1.0" encoding="utf-8"?>
<d:error xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
  <s:exception>Sabre\DAV\Exception\NotFound</s:exception>
  <s:message>Principal with name dff not found</s:message>
</d:error>
<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns"% 

I think the problem exists in the DAV lib: https://github.com/sabre-io/dav/blob/master/lib/DAV/Server.php#L1640. $w->openUri('php://output'); will be called, then $this->writeMultiStatus($w, $fileProperties, $strip404s);. This is the place where exceptions will be thrown in case of an invalid request. Because exceptions are not catched here, $w->flush(); will never be called -> the stream doesn't end properly -> bad.

With something like this it works for me:

try {
    $this->writeMultiStatus($w, $fileProperties, $strip404s);
} catch (\Exception $e) {
    $w->flush();
    throw $e;
}

2 things I'm currently not sure of:

  • Why are our errors thrown in writeMultiStatus()? Is this the "normal"/recommended way?
  • Can we hook into this call somehow to fix it? Doesn't look like so to me...

@DeepDiver1975
Copy link
Member Author

My expectation would be that writeMultiStatus never throws an exceptions.

This is what I was mentioning earlier: we need to make sure that either all conditions which could throw an exception are caught earlier.
Or that in case of an exception within writeMultiStatus we catch it locally and write the corresponding status within the multi status

@AlexAndBear AlexAndBear force-pushed the feature/sabre-with-streaming-propfind-reloaded branch from a15a344 to c49dc1c Compare October 7, 2021 10:59
.htaccess Outdated Show resolved Hide resolved
@AlexAndBear AlexAndBear force-pushed the feature/sabre-with-streaming-propfind-reloaded branch from f149d0b to d49e3c3 Compare October 7, 2021 11:48
@JammingBen JammingBen force-pushed the feature/sabre-with-streaming-propfind-reloaded branch 4 times, most recently from c8f8cef to 9932411 Compare October 7, 2021 12:51
@JammingBen
Copy link
Contributor

JammingBen commented Oct 7, 2021

@DeepDiver1975 Pipeline runs now, please have a look. We basically just added a preflight check if the tree is traversable and if the resource has read permissions in case of a share.

Regarding the open to-dos, please verify the following assumptions:

  • capability -> we just add depth_infinity to the capabilities and set it to true
  • enable streaming only if depth: infinity is used (risk minimization) -> That's outdated, we always enable streaming
  • Unit tests need to be added
  • Acceptance tests need to be added (maybe @phil-davis and his team can support us here)

@JammingBen JammingBen added 2 - Developing app:dav php Pull requests that update Php code labels Oct 7, 2021
@DeepDiver1975
Copy link
Member Author

* `capability` -> we just add `depth_infinity` to the capabilities and set it to `true`

please double check if this shall be configurable @michaelstingl @pmaier1

* `enable streaming only if depth: infinity is used (risk minimization)` -> That's outdated, we always enable streaming

👍

* Unit tests need to be added

👍

* Acceptance tests need to be added (maybe @phil-davis and his team can support us here)

👍

@pmaier1
Copy link
Contributor

pmaier1 commented Oct 7, 2021

please double check if this shall be configurable @michaelstingl @pmaier1

Please make it configurable, default on. So that we have an easy way to disable it if we encounter issues.

@JammingBen JammingBen force-pushed the feature/sabre-with-streaming-propfind-reloaded branch from 0d9d5be to 9932411 Compare October 8, 2021 07:20
@AlexAndBear
Copy link

@pmaier1 @DeepDiver1975 what should happen if depth_infinity is set to false and the client does a propfind with this header, should we throw an error?

@pmaier1
Copy link
Contributor

pmaier1 commented Oct 8, 2021

@pmaier1 @DeepDiver1975 what should happen if depth_infinity is set to false and the client does a propfind with this header, should we throw an error?

How do we handle it today?

@JammingBen
Copy link
Contributor

PROPFIND with depth=infinity fails if dav.propfind.depth_infinity is set to false
PROPFIND with depth=infinity succeeds if dav.propfind.depth_infinity is set to true (which is default)

I adjusted an existing acceptance test to match these scenarios.

Is there an acceptance test for propfind on a folder which has external storages inside which are (temporarily) not available?

I couldn't find it, but maybe @phil-davis knows.

@JammingBen JammingBen marked this pull request as ready for review October 11, 2021 12:57
config/config.sample.php Outdated Show resolved Hide resolved
Copy link
Member

@IljaN IljaN left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some optional remarks/thought. LGTM 👍

apps/dav/lib/Connector/Sabre/FilesPlugin.php Show resolved Hide resolved
apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php Outdated Show resolved Hide resolved
apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php Outdated Show resolved Hide resolved
@phil-davis
Copy link
Contributor

Is there an acceptance test for propfind on a folder which has external storages inside which are (temporarily) not available?

Nothing that I am aware of. I don't remember ever coding something that would "pull out the external storage backend" during a test scenario.

Copy link
Contributor

@phil-davis phil-davis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@JammingBen
Copy link
Contributor

Nothing that I am aware of. I don't remember ever coding something that would "pull out the external storage backend" during a test scenario.

@phil-davis Could you help us implementing such test?

@phil-davis
Copy link
Contributor

Could you help us implementing such test?

@JammingBen we can try. Please create an issue and assign me. If we can do it with "local storage" then it might be easy enough (rename the local storage folder, try some API actions, rename the folder back again, try the API again)

@AlexAndBear AlexAndBear force-pushed the feature/sabre-with-streaming-propfind-reloaded branch from 8233bf3 to daa44f4 Compare October 13, 2021 08:31
@AlexAndBear AlexAndBear force-pushed the feature/sabre-with-streaming-propfind-reloaded branch from daa44f4 to 300d314 Compare October 13, 2021 09:41
@AlexAndBear AlexAndBear force-pushed the feature/sabre-with-streaming-propfind-reloaded branch from 300d314 to 2914ec2 Compare October 13, 2021 12:16
@sonarcloud
Copy link

sonarcloud bot commented Oct 13, 2021

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 1 Code Smell

72.0% 72.0% Coverage
0.0% 0.0% Duplication

@AlexAndBear AlexAndBear merged commit 8b74370 into master Oct 13, 2021
@delete-merged-branch delete-merged-branch bot deleted the feature/sabre-with-streaming-propfind-reloaded branch October 13, 2021 13:07
@jnweiger
Copy link
Contributor

jnweiger commented Nov 22, 2021

Capability for recursive propfind confirmed in 10.9.0 beta1:

curl -k -s -u admin:admin 'https://localhost/ocs/v1.php/cloud/capabilities?format=json' | jq .ocs.data.capabilities.dav.propfind
{
  "depth_infinity": true
}

But no capabiltiy seen, that mentions streaming. Probably OK.

@jnweiger
Copy link
Contributor

Confirmed fixed in 10.9.0 RC2

  • On a tree with 40000 files and folders, the first output appears conistently within 10 seconds:
  • curl -k -s -u admin:admin -XPROPFIND https://$server/remote.php/dav/files/admin/Deep -H "Depth:infinity" | pv > /dev/null
  • total wall clock time: 43 sec.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
app:dav php Pull requests that update Php code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Depth infinity: Make recursive PROPFIND calls cheaper