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

Remove the need of temp files from the handling of Range requests #623

Merged
merged 2 commits into from Apr 2, 2015

Conversation

dratini0
Copy link
Contributor

@dratini0 dratini0 commented Apr 1, 2015

This commit requires sabre-io/http#45 to work.

The other day, I tried to play a 10 gig HD movie from my Owncloud server through GVFS. It failed, and hanged my server by forcing PHP to create humongous temp files. (see owncloud/core#15321) As it turns out, the problem was with HTTP Range requests: SabreDAV decided to create temp files with the the entire contents of the range (GVFS requested ranges like 40960-). So I went ahead to create this pair of small patches.

I am looking forward to hearing your opinion on the matter. Sorry for not opening a discussion beforehand, but discussing it would have taken longer than writing it.

And yes, with these applied, I have managed to play the video, at least in a separate SabreDAV install.

Requires the matching commit for sabre-http, which makes sendResponse respect Content-Length. Also adjusted the unit tests to reflect these changes.
// fseek will return 0 only if $stream is seekable (and -1 otherwise)
// for a seekable $body stream we simply set the pointer
// for a non-seekable $body stream we read and discard just the
// right amount of data
Copy link
Member

Choose a reason for hiding this comment

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

One extra space before right.

@Hywan
Copy link
Member

Hywan commented Apr 2, 2015

Good idea and I like the new solution. More clever and straightforward.

However (I think it is not related to this new patch but it applies in all situations), what if we ask for a range from 42-100 and the stream only contains 7 bytes. Another scenario is if the stream is corrupted. The $consumed variable will never reach the $start variable and we will have an infinite loop. I think we must detect if $consumed stagnates (does not increase) during 2 steps in the loop, or if we reach the end of the stream. The latter solution is more elegant because we can use feof. Nevertheless, remind the stream can be corrupted, the algorithm could therefore never reach the end of the stream and feof is inefficient. Consequently, I propose to add an invariant checking $consumed increases at each step, something like this:

for ($previousConsumed = $consumed = 0; $start - $consumed > 0;) {

    fread($body, min($start - $consumed, $consume_block));
    $consumed = ftell($body);

    if (!($previousConsumed < $consumed)) {
        // break
        throw new Exception(…); // don't know which exception
    }

    $previousConsumed = $consumed;
}

We could add the invariant $previousConsumed < $consumed in the for(…; $invariant;) but we would not be able to throw an exception. And I think it clarifies the code.

@evert
Copy link
Member

evert commented Apr 2, 2015

Love the idea and the quality of the patch. Really great.

evert added a commit that referenced this pull request Apr 2, 2015
Remove the need of temp files from the handling of Range requests
@evert evert merged commit 44a63f8 into sabre-io:master Apr 2, 2015
@dratini0
Copy link
Contributor Author

dratini0 commented Apr 2, 2015

That is nice to hear! 😄

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

Successfully merging this pull request may close these issues.

None yet

3 participants