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 size;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
size_t start_offset;
|
size_t start_offset;
|
||||||
|
size_t end_offset;
|
||||||
int marked;
|
int marked;
|
||||||
struct transcode_ctx *xcode;
|
struct transcode_ctx *xcode;
|
||||||
};
|
};
|
||||||
|
@ -223,11 +224,23 @@ static void
|
||||||
stream_chunk_raw_cb(int fd, short event, void *arg)
|
stream_chunk_raw_cb(int fd, short event, void *arg)
|
||||||
{
|
{
|
||||||
struct stream_ctx *st;
|
struct stream_ctx *st;
|
||||||
|
size_t chunk_size;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
st = (struct stream_ctx *)arg;
|
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)
|
||||||
{
|
{
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
|
@ -278,23 +291,47 @@ httpd_stream_file(struct evhttp_request *req, int id)
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
const char *param;
|
const char *param;
|
||||||
|
const char *param_end;
|
||||||
char buf[64];
|
char buf[64];
|
||||||
long offset;
|
long offset;
|
||||||
|
long end_offset;
|
||||||
int transcode;
|
int transcode;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
end_offset = 0;
|
||||||
param = evhttp_find_header(req->input_headers, "Range");
|
param = evhttp_find_header(req->input_headers, "Range");
|
||||||
if (param)
|
if (param)
|
||||||
{
|
{
|
||||||
DPRINTF(E_DBG, L_HTTPD, "Found Range header: %s\n", param);
|
DPRINTF(E_DBG, L_HTTPD, "Found Range header: %s\n", param);
|
||||||
|
|
||||||
|
/* Start offset */
|
||||||
ret = safe_atol(param + strlen("bytes="), &offset);
|
ret = safe_atol(param + strlen("bytes="), &offset);
|
||||||
if (ret < 0)
|
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;
|
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);
|
mfi = db_file_fetch_byid(id);
|
||||||
|
@ -396,6 +433,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
st->offset = offset;
|
st->offset = offset;
|
||||||
|
st->end_offset = end_offset;
|
||||||
|
|
||||||
/* Content-Type for video files is different than for audio files
|
/* Content-Type for video files is different than for audio files
|
||||||
* and overrides whatever may have been set previously, like
|
* 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->start_offset = offset;
|
||||||
st->req = req;
|
st->req = req;
|
||||||
|
|
||||||
if (offset == 0)
|
if ((offset == 0) && (end_offset == 0))
|
||||||
evhttp_send_reply_start(req, HTTP_OK, "OK");
|
evhttp_send_reply_start(req, HTTP_OK, "OK");
|
||||||
else
|
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",
|
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)))
|
if ((ret < 0) || (ret >= sizeof(buf)))
|
||||||
DPRINTF(E_LOG, L_HTTPD, "Content-Range too large for buffer, dropping\n");
|
DPRINTF(E_LOG, L_HTTPD, "Content-Range too large for buffer, dropping\n");
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in New Issue