Add support for end offset in Range header
Honor end offset provided in the Range header and do not stream more than what the client asked for. Based on a patch by Ace Jones <ace.jones1@yahoo.com>.
This commit is contained in:
parent
b9e7df5be3
commit
ff89ce0183
48
src/httpd.c
48
src/httpd.c
|
@ -80,6 +80,7 @@ struct stream_ctx {
|
|||
size_t size;
|
||||
size_t offset;
|
||||
size_t start_offset;
|
||||
size_t end_offset;
|
||||
int marked;
|
||||
struct transcode_ctx *xcode;
|
||||
};
|
||||
|
@ -223,11 +224,23 @@ static void
|
|||
stream_chunk_raw_cb(int fd, short event, void *arg)
|
||||
{
|
||||
struct stream_ctx *st;
|
||||
size_t chunk_size;
|
||||
int ret;
|
||||
|
||||
st = (struct stream_ctx *)arg;
|
||||
|
||||
ret = evbuffer_read(st->evbuf, st->fd, STREAM_CHUNK_SIZE);
|
||||
if (st->end_offset && (st->offset > st->end_offset))
|
||||
{
|
||||
stream_end(st, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (st->end_offset && ((st->offset + STREAM_CHUNK_SIZE) > (st->end_offset + 1)))
|
||||
chunk_size = st->end_offset + 1 - st->offset;
|
||||
else
|
||||
chunk_size = STREAM_CHUNK_SIZE;
|
||||
|
||||
ret = evbuffer_read(st->evbuf, st->fd, chunk_size);
|
||||
if (ret <= 0)
|
||||
{
|
||||
if (ret == 0)
|
||||
|
@ -278,23 +291,47 @@ httpd_stream_file(struct evhttp_request *req, int id)
|
|||
struct stat sb;
|
||||
struct timeval tv;
|
||||
const char *param;
|
||||
const char *param_end;
|
||||
char buf[64];
|
||||
long offset;
|
||||
long end_offset;
|
||||
int transcode;
|
||||
int ret;
|
||||
|
||||
offset = 0;
|
||||
end_offset = 0;
|
||||
param = evhttp_find_header(req->input_headers, "Range");
|
||||
if (param)
|
||||
{
|
||||
DPRINTF(E_DBG, L_HTTPD, "Found Range header: %s\n", param);
|
||||
|
||||
/* Start offset */
|
||||
ret = safe_atol(param + strlen("bytes="), &offset);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_HTTPD, "Invalid offset, starting from 0 (%s)\n", param);
|
||||
DPRINTF(E_LOG, L_HTTPD, "Invalid start offset, will stream whole file (%s)\n", param);
|
||||
offset = 0;
|
||||
}
|
||||
/* End offset, if any */
|
||||
else
|
||||
{
|
||||
param_end = strchr(param, '-');
|
||||
if (param_end)
|
||||
{
|
||||
ret = safe_atol(param_end + 1, &end_offset);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_HTTPD, "Invalid end offset, will stream to end of file (%s)\n", param);
|
||||
end_offset = 0;
|
||||
}
|
||||
|
||||
if (end_offset < offset)
|
||||
{
|
||||
DPRINTF(E_LOG, L_HTTPD, "End offset < start offset, will stream to end of file (%ld < %ld)\n", end_offset, offset);
|
||||
end_offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mfi = db_file_fetch_byid(id);
|
||||
|
@ -396,6 +433,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
|
|||
return;
|
||||
}
|
||||
st->offset = offset;
|
||||
st->end_offset = end_offset;
|
||||
|
||||
/* Content-Type for video files is different than for audio files
|
||||
* and overrides whatever may have been set previously, like
|
||||
|
@ -487,14 +525,14 @@ httpd_stream_file(struct evhttp_request *req, int id)
|
|||
st->start_offset = offset;
|
||||
st->req = req;
|
||||
|
||||
if (offset == 0)
|
||||
if ((offset == 0) && (end_offset == 0))
|
||||
evhttp_send_reply_start(req, HTTP_OK, "OK");
|
||||
else
|
||||
{
|
||||
DPRINTF(E_DBG, L_HTTPD, "Stream request with offset %ld\n", offset);
|
||||
DPRINTF(E_DBG, L_HTTPD, "Stream request with range %ld-%ld\n", offset, end_offset);
|
||||
|
||||
ret = snprintf(buf, sizeof(buf), "bytes %ld-%ld/%ld",
|
||||
offset, (long)sb.st_size, (long)sb.st_size + 1);
|
||||
offset, (end_offset) ? end_offset : (long)sb.st_size, (long)sb.st_size);
|
||||
if ((ret < 0) || (ret >= sizeof(buf)))
|
||||
DPRINTF(E_LOG, L_HTTPD, "Content-Range too large for buffer, dropping\n");
|
||||
else
|
||||
|
|
Loading…
Reference in New Issue