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

fix: handle client disconnect properly with ignore_user_abort true #207

Conversation

kesselb
Copy link
Contributor

@kesselb kesselb commented May 24, 2023

#205 but with tests ;)

ignore_user_abort(true) instruct php to not abort the script on client disconnect. To avoid reading the entire stream and dismissing the data afterward, check between the chunks if the client is still there.

@kesselb kesselb force-pushed the handle-connection-abort-with-ignore-user-abort branch 3 times, most recently from 7ae9f26 to 1df4a84 Compare May 24, 2023 21:35
@codecov
Copy link

codecov bot commented May 25, 2023

Codecov Report

Merging #207 (f2a1635) into master (c2cd0a5) will decrease coverage by 0.11%.
The diff coverage is 50.00%.

❗ Current head f2a1635 differs from pull request most recent head c574923. Consider uploading reports for the commit c574923 to get more accurate results

@@             Coverage Diff              @@
##             master     #207      +/-   ##
============================================
- Coverage     94.50%   94.40%   -0.11%     
- Complexity      256      258       +2     
============================================
  Files            15       15              
  Lines           873      875       +2     
============================================
+ Hits            825      826       +1     
- Misses           48       49       +1     
Impacted Files Coverage Δ
lib/Sapi.php 98.13% <50.00%> (-0.92%) ⬇️

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@yevon
Copy link

yevon commented Jun 10, 2023

Hi, any news on this one? Thanks!

@FedericoHeichou
Copy link

Why hasn't it been merged yet? This commit fixed all my problems with streaming and downloads

@szaimen
Copy link

szaimen commented Jun 20, 2023

@staabm could you please have a look at the PR? Thanks a lot! :)

Copy link
Member

@staabm staabm left a comment

Choose a reason for hiding this comment

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

looks great thanks - verified the test locally.

@staabm
Copy link
Member

staabm commented Jun 21, 2023

@phil-davis do you have an idea on the cs error on php7.4 only?

ignore_user_abort(true) instruct php to not abort the script on client disconnect.
To avoid reading the entire stream and dismissing the data afterward, check between the chunks if the client is still there.

Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>
@phil-davis phil-davis force-pushed the handle-connection-abort-with-ignore-user-abort branch from 1df4a84 to f2a1635 Compare June 26, 2023 09:01
@phil-davis
Copy link
Contributor

I fixed CI with PR #208 and then rebased here.

@phil-davis
Copy link
Contributor

And pushed a small change to get phpstan passing.

// Abort on client disconnect.
// With ignore_user_abort(true), the script is not aborted on client disconnect.
// To avoid reading the entire stream and dismissing the data afterward, check between the chunks if the client is still there.
if (1 === ignore_user_abort() && 1 === connection_aborted()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

https://www.php.net/manual/en/function.ignore-user-abort.php
This PHP function does return an int - looking at its name, I would have assumed it returned a bool !
So this code does look OK.

Copy link
Member

Choose a reason for hiding this comment

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

I had the same experience ;)

Copy link
Member

Choose a reason for hiding this comment

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

just figured, I should cover this better in PHPStan: phpstan/phpstan-src#2489

Copy link
Member

Choose a reason for hiding this comment

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

also connection_aborted impurity will be covered by phpstan/phpstan-src#2555

@staabm
Copy link
Member

staabm commented Jun 26, 2023

And pushed a small change to get phpstan passing.

awesome, thanks phil.

@phil-davis phil-davis merged commit 97c8184 into sabre-io:master Jun 26, 2023
@phil-davis
Copy link
Contributor

I will sort out backporting this (and any other recent fixes) to the 6.x and 5.x release series.

sabre/dav currently only uses sabre/http v5, and it would be nice to have the fixes picked up there by a patch release(s) here in sabre/http

@phil-davis phil-davis mentioned this pull request Jun 26, 2023
@phil-davis
Copy link
Contributor

This fix is now available in 5.1.7 6.0.1 and 7.0.1

@yevon
Copy link

yevon commented Jul 21, 2023

This should be reopened, 27.0.1 did not fix the issue. Nextcloud keeps downloading full files even after canceling the file download. Just try to download a 100gb file and cancelling it immediately. You can execute this command to check it out:

sudo iotop -o -a

@FedericoHeichou
Copy link

FedericoHeichou commented Jul 21, 2023

This should be reopened, 27.0.1 did not fix the issue. Nextcloud keeps downloading full files even after canceling the file download. Just try to download a 100gb file and cancelling it immediately. You can execute this command to check it out:

sudo iotop -o -a

I bet you are not using the patched version.
Check with composer and update the library https://github.com/nextcloud/3rdparty/tree/v27.0.1

@yevon
Copy link

yevon commented Jul 21, 2023

Sorry I jumped here from a linked nextcloud issue instead of nextcloud repo! haha, they have not fixed the issue, not sabre!

@FedericoHeichou
Copy link

Sorry I jumped here from a linked nextcloud issue instead of nextcloud repo! haha, they have not fixed the issue, not sabre!

Np, I am the one who linked the PR to that issue.
In this moment I can't try to reproduce the issue, maybe I'll try the next week, but the parts using sabre in the correct way should work.
I suggest to add more informations in your comment in the nextcloud issue, else I don't know if someone can reproduce it

@szaimen
Copy link

szaimen commented Jul 21, 2023

The issue is fixed with Nextcloud 28 which is not released yet.

// Abort on client disconnect.
// With ignore_user_abort(true), the script is not aborted on client disconnect.
// To avoid reading the entire stream and dismissing the data afterward, check between the chunks if the client is still there.
if (1 === ignore_user_abort() && 1 === connection_aborted()) {
Copy link

Choose a reason for hiding this comment

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

I'd assume 0 means false and 1 is true?
If so, this code falsely breaks when the connection was aborted AND we want to ignore that?

Or did i mix something up?

Copy link
Contributor

Choose a reason for hiding this comment

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

https://www.php.net/manual/en/function.ignore-user-abort.php

1 === ignore_user_abort() means "ignore user abort has been enabled" (somewhere in "the system" or "the code" prior to this point)

1 === connection_aborted() means that a connection has "gone away".

When these 2 things both happen, we are deciding, for this "manual" stream-copy loop, we do want to stop feeding the stream copy (even though "the system" has enabed ignore_user_abort()). Because we know that it is pointless to keep looping and pushing out chunk-size bytes each time.

@yevon
Copy link

yevon commented Jul 23, 2023

If the system setting is ignored (ignore_user_abort) why is it even checked? It should abort in both cases and with just1 === connection_aborted() is not enough? It is aborted automatically if system setting is enabled?

@phil-davis
Copy link
Contributor

connection_aborted() is not enough?

That is probably correct. But the extra check is not going to break anything (or cause any different behavior, IMO!). So I guess we leave the code as it is.

@proxima235
Copy link

I've checked out these fixes are working on my instance. But they don't make any changes in the case of link-sharing. My Nextcloud does not stop reading the file when accessed via a public link.
How can I make these fixes cover the case of link-sharing?

@staabm
Copy link
Member

staabm commented Aug 8, 2023

IMO the PR only works with chunked requests or range requests.

How do your http requests look like?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants