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

Support HTTP Byte Serving via Ranges header #93

Open
ojensen5115 opened this issue Feb 3, 2017 · 10 comments
Open

Support HTTP Byte Serving via Ranges header #93

ojensen5115 opened this issue Feb 3, 2017 · 10 comments

Comments

@ojensen5115
Copy link

Currently, if you have a <video> tag whose src is served through staticfile, seeking doesn't work. This can be fixed by supporting Byte Serving.

@Hoverbear
Copy link

This would be awesome! :) If anyone wants to pick this up please let us know and we can try to help!

@Cobrand
Copy link

Cobrand commented Feb 6, 2017

I'd like to pick this up. If I run into trouble I'll let you know.

Funnily enough, video playback doesn't work at all with staticfile, let alone seeking. Any video just refuses to play, either via firefox or via mpv. The same video works if played with firefox or mpv and if the video is hosted with an apache. I wonder if it's related ?

I will try to dig this up and come back with some news.

@untitaker
Copy link
Member

I suspect usage of X-Sendfile will fix this too.

@ojensen5115
Copy link
Author

@Cobrand on my end, video playback works fine (in Chrome), it's just seeking that doesn't work. (note if you don't set autoplay and/or controls in the <video> tag, you'll need to tell the video to play via context menu.

@Cobrand
Copy link

Cobrand commented Feb 6, 2017

Turns out that I tested with mp4, and it doesn't work in iron at all (probably because it can't seek metadata ?). webm either works without seeking in mpv, or hangs in the middle for long videos (> 30s). So that's definitely our issue here.

For info, the difference between Iron and Apache :

Iron

HTTP/1.1 200 OK
Content-Length: 29271156
Content-Type: video/webm
Date: Mon, 06 Feb 2017 19:20:56 GMT

Apache

HTTP/1.1 200 OK
Accept-Ranges: bytes
Connection: Keep-Alive
Content-Length: 29271156
Content-Type: video/webm
Date: Mon, 06 Feb 2017 19:21:57 GMT
ETag: "1bea474-54227ffe25f38"
Keep-Alive: timeout=5, max=100
Last-Modified: Fri, 25 Nov 2016 22:54:07 GMT
Server: Apache/2.4.25 (Unix) PHP/7.1.1

@Cobrand
Copy link

Cobrand commented Feb 6, 2017

So I dug a little bit into how this stuff works, and I have some questions.

Basically if you answer with the Accept-Range: bytes header, you must be able to receive and process the Range header (event though you can still ignore the Range header).
Basically a client can request things like these (one line = one different request) :

Range: bytes=0-
Range: bytes=200-
Range: bytes=200-1000, 2000-3000, 4000-

First one is dead simple: just send a "File" like we used to do.

Second one is less simple but feasible: Answer with the proper Content-Range, and offset the file by 200 bytes (from a File struct using a Bytes Iterator I guess)

Third one is way less simple, you have to answer something like this according to RFC 2046 :

Content-type: multipart/byteranges; boundary="xxironstaticfileboundaryxx"

--xxironstaticfileboundaryxx
Content-type: application/octet-stream;

200 to 1000 bytes here
--xxironstaticfileboundaryxx
Content-type: application/octet-stream;

2000 to 3000 bytes here...
--xxironstaticfileboundaryxx
Content-type: application/octet-stream;

4000 bytes to end of file here

--xxironstaticfileboundaryxx--

This is technically what we must answer, but unfortunately there is no proper way to answer a multipart body in Iron as of now, so for now I guess I'll pass.

I guess there might also be a way to only reply bytes 200 to 1000, but not only this isn't mentioned as allowed or forbidden in the RFCs, but I don't really know what to answer as well. Do we just answer as if only one range was asked, and we just set the Content-Length and Content-Range accordingly ?

For info, Apache will answer this to a Range: bytes=1000-2000, 3000-4000 request:

Content-Length: 2208
Content-Type: multipart/byteranges; boundary=beb42d06bc54e552

(2208 instead of 2000 is because the delimiter + "Content-type: video/webm" + "Content-range: bytes 3000-4000/29271156" are added as well, twice)

Since we can choose to ignore the "Range" header, I guess we can choose to ignore it when we got more than 1 range as well.

So yeah if someone knows If I can answer only bytes 1000 to 2000 for a request "Range: bytes=1000-2000, 3000-4000", that'd be great.

@untitaker
Copy link
Member

You could just ignore the range request if it's composed of multiple ranges for now.

Cobrand added a commit to Cobrand/staticfile that referenced this issue Feb 7, 2017
This commits adds Partial Content Delivery, as asked in issue iron#93. This
enables the "Accept-Ranges" header on all files delivered via
static. It is possible to ask only a certain portion of bytes like
explicitely described in RFC 7233. Of the 3 ways to ask for a range of
bytes (byte x to byte y, everything from byte x to end of file, last y
bytes from end of file), every one of them is implemented, but if a
request is to ask multi ranges in a same request, this implementation
will only account the first range.
@Cobrand
Copy link

Cobrand commented Feb 13, 2017

Can someone have a look at PR #95 ?

@ojensen5115
Copy link
Author

I'm very excited to see this -- it turns a simple "serve this folder" webserver into something significantly more useful than python's equivalent, especially in the case of e.g. a home media server.

@Cobrand
Copy link

Cobrand commented Apr 13, 2017

I totally forgot that I used to have a PR open about that ... I'll try to find some time to get this PR fixed and merged once for all

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

Successfully merging a pull request may close this issue.

4 participants