Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
A patch that adds file transfer resume support by accepting byte ranges and sending 'HTTP/1.1 206 Partial Content' in private file handling.
Comment | File | Size | Author |
---|---|---|---|
#47 | file_transfer_range.zip | 3.95 KB | KarstenS |
#43 | file_transfer_range.zip | 3.77 KB | syakely |
#34 | file_transfer_range.zip | 2.35 KB | edhel |
#29 | file.inc-91934-29_HEAD.patch | 5.4 KB | Darren Oh |
#28 | file.inc-91934-28_HEAD.patch | 5.5 KB | Darren Oh |
Comments
Comment #1
Steven CreditAttribution: Steven commented$r-1024;
.http://www.faqs.org/rfcs/rfc2616.html
Comment #2
isoteemu CreditAttribution: isoteemu commentedThanks for feedback, but dang, comp^Wsuggestion list is bigger than my patch. Taking the hint.
True, I had missed the 416 header part, so I added it. Next I changed it to use preg_match(), but alas, I had been in delusion that regexes should be avoided in simple cases, as they're suppose to be a bit expensive to do. But call me a dumm, as what I can't understand where is that you would like to use min/max. In comparison?
And I think I was a bit rushing, as looking a "correct" way of handling ranges from apache source revealed that there is much more than meets the eye at first sight. So I'll close this and let it wait in my own tree for infinite future.
Comment #3
9802008 CreditAttribution: 9802008 commentedThanks! This solved the problem I was having with windows media player: http://drupal.org/node/102167
Comment #4
Darren OhToo often an imperfect contribution is criticized so strongly that it seems no contribution would have been preferred. Supporting pause and resume for downloads is an important feature. The flaws in this patch should motivate other developers to work on it.
Comment #5
Darren OhHere's an up-to-date patch for Drupal 4.7.
Comment #6
Darren OhAnd one for HEAD. I set it to "needs review" for testing, not so that the previous criticisms could be repeated.
Comment #7
Darren OhFile was missing.
Comment #8
Darren OhCleaned up code and replaced header() with drupal_set_header().
Comment #9
Darren OhStill trying to meet the vague "messiness" objection.
Comment #10
Darren OhCompletely rewritten patch to implement the full HTTP spec.
Comment #11
Stefan Nagtegaal CreditAttribution: Stefan Nagtegaal commentedHow should this be tested?
Comment #12
Darren OhTwo ways: with a download manager that supports pause and resume, and by jumping past the downloaded portion of a song in a music player.
Comment #13
Darren OhRealPlayer works well for testing the seek function. Cancelling and restarting a download in FireFox is a good test of the pause and resume function. Make sure to set downloads to private for a valid test.
After some testing on my own, I modified the patch.
Comment #14
Darren OhMissed an error.
Comment #15
Stefan Nagtegaal CreditAttribution: Stefan Nagtegaal commentedNice! Coding style looks good and functionality seems to work on FF win/OSX and Opera Win/OSX.
This is RTBC.
Comment #16
Darren OhAdding support for a basic HTTP feature is a simple change that can be done now.
Comment #17
Gábor HojtsyHm, I looked through http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35 which says that:
Which means to me that if multiple ranges are requested, all ranges should be returned combined. This code does not seem like doing that from what I see. It does move the file pointer to the latest range and sets the length to the latest range requested. Seems to be printing out Content-Range headers for all satisfiable ranges but then only returning the last one. Do I misunderstand the standards or the code?
Comment #18
Darren OhYou caught a bug. Updated patch attached.
Comment #19
Wim LeersPatch wasn't created from root. Reroll.
Comment #20
Darren OhI'd call it ready.
Comment #21
Dries CreditAttribution: Dries commentedThis is a new feature and needs to wait for Drupal 7. Thanks.
Comment #22
cburschkaPatch still applies to HEAD, but with offset. Here's a reroll.
Comment #23
drewish CreditAttribution: drewish commentedlooking at the RFC i'm still not sure this is correct: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16
it doesn't seem like we'd be returning multipart media.
i'd like to see _file_transfer_range() take a starting offset rather than having to know that you need to fseek() before calling it.
also, the new string concatenation rules aren't followed.
Comment #24
drewish CreditAttribution: drewish commentedmarked #49868: Download Resume support. as a duplicate
Comment #25
Darren OhComment #26
Darren OhSet Last-Modified and ETag headers based on file modification time to support download pause/resume.
Comment #27
lilou CreditAttribution: lilou commentedThe patch #26 cannot apply against CVS HEAD.
Comment #28
Darren OhComment #29
Darren OhKeeping up with HEAD.
Comment #30
drewish CreditAttribution: drewish commentedthis code just seems scary and easy to screw up. i'm of the opinion that we could do this in contrib using the technique i've outlined here: http://drupal.org/node/74472#comment-1052308
Comment #32
lilou CreditAttribution: lilou commentedTest failure : #335122: Test clean HEAD after every commit
Comment #33
catchThis does look like something which might be better suited for contrib. Or at least it needs tests - should at least be able to check headers.
Comment #34
edhel CreditAttribution: edhel commentedI've made module based on last patch of Darren Oh (http://drupal.org/comment/reply/91934#comment-1070336) and advice of drewish (http://drupal.org/comment/reply/91934#comment-1070346). See attachment.
It seems work on my site, though it's not tested in detail yet.
Comment #35
batje CreditAttribution: batje commentedsubscribe
Comment #36
grendzy CreditAttribution: grendzy commentedI think this would be a great core feature, and would make private transfers more consistent with public file behavior (Apache, at least, has the byteranges filter enabled by default). In addition to resumable downloads, byte range requests are used by the iPhone (and probably other mobile devices) to emulate video streaming over plain HTTP.
For those looking for a contrib solution, the X-Sendfile will also solve this problem.
Comment #37
grendzy CreditAttribution: grendzy commentedIf I'm reading the RFC correctly, this is off by one. $end_file + $range should use $filesize instead.
Regarding the "scariness" factor, it's quite easy to write tests for this code, and it's not something that will need to change very often (not until the HTTP spec is changed, probably). Here's a sample of what tests would look like:
This review is powered by Dreditor.
Comment #38
Cyberwolf CreditAttribution: Cyberwolf commentedI took a look at this module. There seems to be some weird code path though:
There is no case in which the else block will get executed. Is the condition right? Or can the control structure be completely removed and just keep what is in the if block?
Comment #39
cburschkaEither the "1" is supposed to become some variable or setting, or it's debug code and the condition can be safely removed.
Edit: Wait, if the patch enters core, we won't need the contrib module anyway.
Comment #40
sinasalek CreditAttribution: sinasalek commentedSubscribed
Comment #41
Nick Robillard CreditAttribution: Nick Robillard commentedConfirming that #34 works as expected for my Drupal 6.20 site.
Comment #42
christianblaze CreditAttribution: christianblaze commentedHas anyone made a D7 version of this(#34)? I tried the sendfile one, but doesn't seem to work...just want somthing likle this except for D7...
Comment #43
syakely CreditAttribution: syakely commentedThank You Drupal Community!!
We were having issues with D7 private videos playing in chrome and safari. redhatmatt and I had an fierce collaborative race to get this module ported to D7.
The module could use some cleaning up and fine tuning, but it is working for us as is.
It's not perfect but instead of sitting on it until it is, or we forget about it, we are returning it back into the wild.
thanks,
SY.
Comment #44
Wim LeersNote that we can (and should!) test the correctness of our implementation using REDbot.
Also note that the implementation I'm using in the CDN module has been proven to work: http://drupalcode.org/project/cdn.git/blob/0f19fca6c4c382cdd751ac97346c0....
Source for that code: http://www.thomthom.net/blog/2007/09/php-resumable-download-server/, now https://bitbucket.org/thomthom/php-resumable-download-server
Comment #45
sinasalek CreditAttribution: sinasalek commentedIt's been a very long time since the beginning of this request , i created a project and committed the modules to let more people use this handy feature till it gets into core.
http://drupal.org/project/resumable_download
Thanks everyone
Comment #46
KarstenS CreditAttribution: KarstenS commentedVote for resumeable download. For a system, that shall get called state of the art, it is a must have.
Missing resume function is also causing issues in most browsers when playing back HTML5 videos stored in private filesystem (no timeline in FF and IE, no autogenerated preview picture in IE, noch playback at all in Safari iOS).
As I've read, HTML5 stuff is one of the big new features of drupal 8.
One more, in my eyes also must have, is a modification of the module "resumeable_download" I've offered here: http://drupal.org/node/1927198
It adds support for returning "304 not modified".
Especially as one focus of drupal 8 is optimizing for mobile devices, reduzing useless traffic (cellular traffic too), should be one important point. Returning 304 is one of them.
Please ignore the file beolow this post as I've worked on the 304 code some time, to get it working much better. The final code is now embedded in the last archive of the thread linked in this post.
Comment #47
KarstenS CreditAttribution: KarstenS commentedComment #48
KarstenS CreditAttribution: KarstenS commentedThat code is not that correct as it should be. The IF_MODIFIED_SINCE is to check for modifications of the file on the server since last request. And you cannot tell for shure, that files will not get exchange by another (I do it for example). So it is not correct to general return 304, when a browser requests this check, because a modified file will never get delivered this way. Also this value really has not much to do with the expiration you have explained in the comment. When there is a cache between user and server, that handles this expiration, the request will never reach the server.
Please take a look at my 304 code here: http://drupal.org/node/1927198
This part contains variables and functions, that are part of the module:
The expiration thing is for caches like proxies (when used, I do not), that tells, how long they can cache the file, before they request it from the server again.
Here should be used, what is setup in admin/config/development/performance, and not a static value. Not everybody wants their files in proxycaches till end of all days and as long as this setting does exist, it should not get ignored.
This is wrong too. There should be the timestamp of the last filechange get sent.
Example:
Comment #49
Darren OhComment #50
Dave Reidfile_transfer no longer exists and is replaced by BinaryFileResponse which seems to support Content-Range and partial downloads. #1561362: Change file_transfer() to use BinaryFileResponse
Comment #51
JvE CreditAttribution: JvE commentedSo this feature is definitely not going into D7?
Comment #52
KarstenS CreditAttribution: KarstenS commentedThat I also would like to know, as I've big trouble to stream large videos from private file system. The webserver is giong to crash completely (fastest when streaming to my iPhone 4) and I really don't know, is it a drupal or a server issue.
Comment #53
sinasalek CreditAttribution: sinasalek commentedYou must use more advanced solution for streaming like that, PHP is not suitable, you can try this module https://drupal.org/project/xsend
Comment #54
KarstenS CreditAttribution: KarstenS commentedThat plugin is for drupal 5 and 6. Not 7.
Also it is Apache2 only.
I'm running lighttpd.
Comment #55
Darren OhThe patch for Drupal 7 was rejected because the Drupal 7 menu system makes it possible to override Drupal’s private file handling in a contrib module. I do not know of any project for such a contrib module. I only ported the patch to Drupal 7 because I needed this feature in Drupal 6, so I lost interest.
Comment #56
Shiraz DindarIt's 2020 and I don't know if this will help anyone but #34 fixed my issue with Safari not playing videos stored in private files, in Drupal 7.