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

range: New http_GetContentRange() semantics #4091

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 29 additions & 5 deletions bin/varnishd/cache/cache_http.c
Original file line number Diff line number Diff line change
Expand Up @@ -873,7 +873,14 @@ http_GetHdrField(const struct http *hp, hdr_t hdr,
return (i);
}

/*--------------------------------------------------------------------*/
/*--------------------------------------------------------------------
* Parse content-length header
*
* Return:
* -2 invalid
* -1 unknown length
* >= 0 body length
*/

ssize_t
http_GetContentLength(const struct http *hp)
Expand All @@ -895,6 +902,20 @@ http_GetContentLength(const struct http *hp)
return (cl);
}

/*--------------------------------------------------------------------
* Parse content-range header
*
* Return:
* -2 invalid
* -1 unknown length
* 0 not applicable
* > 0 full body length
*
* lo, hi:
* -1 unknown position
* >= 0 position
*/

ssize_t
http_GetContentRange(const struct http *hp, ssize_t *lo, ssize_t *hi)
{
Expand All @@ -911,14 +932,14 @@ http_GetContentRange(const struct http *hp, ssize_t *lo, ssize_t *hi)
*lo = *hi = -1;

if (!http_GetHdr(hp, H_Content_Range, &b))
return (-1);
return (0); // No content-range, ignore

t = strchr(b, ' ');
if (t == NULL)
return (-2); // Missing space after range unit

if (!http_range_at(b, bytes, t - b))
return (-1); // Unknown range unit, ignore
return (-2); // Unknown range unit
b = t + 1;

if (*b == '*') { // Content-Range: bytes */123
Expand All @@ -937,6 +958,8 @@ http_GetContentRange(const struct http *hp, ssize_t *lo, ssize_t *hi)
if (*b != '/')
return (-2);
if (b[1] == '*') { // Content-Range: bytes 1-2/*
if (*lo == -1 && *hi == -1)
return (-2); // Content-Range: bytes */*
cl = -1;
b += 2;
} else {
Expand All @@ -950,10 +973,11 @@ http_GetContentRange(const struct http *hp, ssize_t *lo, ssize_t *hi)
return (-2);
if (*lo > *hi)
return (-2);
assert(cl >= -1);
if (cl == -1)
return (-1);
assert(cl > 0);
if (*lo >= cl || *hi >= cl)
return (-2);
AN(cl);
return (cl);
}

Expand Down
12 changes: 6 additions & 6 deletions bin/varnishd/cache/cache_range.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,16 +265,16 @@ VRG_CheckBo(struct busyobj *bo)
return (-1);
}

if (crlo < 0 && crhi < 0 && crlen < 0) {
AZ(http_GetHdr(bo->beresp, H_Content_Range, NULL));
return (0);
}

if (rlo < 0 && rhi < 0) {
if (rlo < 0 && rhi < 0 && crlen != 0) {
VSLb(bo->vsl, SLT_Error, "Unexpected content-range header");
return (-1);
}

if (crlo < 0 && crhi < 0 && crlen == 0) {
AZ(http_GetHdr(bo->beresp, H_Content_Range, NULL));
return (0);
}

if (crlo < 0) { // Content-Range: bytes */123
assert(crhi < 0);
assert(crlen > 0);
Expand Down
34 changes: 33 additions & 1 deletion bin/varnishtest/tests/c00034.vtc
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ varnish v1 -vsl_catchup
server s1 {
loop 2 {
rxreq
txresp -nolen -hdr "Content-Length: 100"
txresp -hdr "Content-Length: 100"
send "0123456789"
send "0123456789"
send "0123456789"
Expand Down Expand Up @@ -210,8 +210,13 @@ varnish v1 -vsl_catchup
server s1 {
rxreq
txresp

rxreq
txresp -hdr "Accept-Ranges: foobar"

rxreq
expect req.http.Range == foobar=1-2
txresp -status 206 -hdr "Content-Range: foobar 1-2/3"
} -start

varnish v1 -vcl+backend {
Expand All @@ -228,10 +233,16 @@ client c7 {
rxresp
expect resp.http.foobar == ""
expect resp.http.accept-ranges == <undef>

txreq
rxresp
expect resp.http.foobar == foobar
expect resp.http.accept-ranges == foobar

txreq -hdr "Range: foobar=1-2"
rxresp
expect resp.status == 503
expect resp.http.content-range == <undef>
} -run

server s1 {
Expand Down Expand Up @@ -265,6 +276,18 @@ server s1 {
rxreq
expect req.http.range == "bytes=0-0"
txresp -hdr "content-range: bytes */*" -bodylen 100

rxreq
expect req.http.range == "bytes=0-0"
txresp -hdr "content-range: bytes 0-0/*" -bodylen 100

# issue 4089
rxreq
expect req.http.range == "bytes=10-19"
txresp -status 206 -hdr "content-range: bytes 10-19/*" \
-hdr "transfer-encoding: chunked"
chunkedlen 10
chunkedlen 0
} -start

varnish v1 -vcl+backend {
Expand Down Expand Up @@ -305,6 +328,15 @@ client c8 {
txreq -hdr "range: bytes=0-0" -hdr "return: pass"
rxresp
expect resp.status == 503

txreq -hdr "range: bytes=0-0" -hdr "return: pass"
rxresp
expect resp.status == 503

# issue 4089
txreq -hdr "range: bytes=10-19" -hdr "return: pass"
rxresp
expect resp.status == 206
} -run

# range filter without a range header
Expand Down
2 changes: 2 additions & 0 deletions include/vrt.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
* Whenever something is deleted or changed in a way which is not
* binary/load-time compatible, increment MAJOR version
*
* NEXT (2024-09-15)
* [cache.h] http_GetContentRange() changed
* 19.0 (2024-03-18)
* [cache.h] (struct req).filter_list renamed to vdp_filter_list
* order of vcl/vmod and director COLD events reversed to directors first
Expand Down