Commit 97434c7c authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Handle Range requests on streaming objects better.

If the client sends [LO]-HI range, we trust it knows something we don't (yet),
and do the Range request.  If we later ran out of data, we close the session.

Other range requests on streaming objects are ignored.

Fixes: #1506
Fixes: #1618
parent cbb03569
......@@ -56,11 +56,14 @@ vrg_range_bytes(struct req *req, enum vdp_action act, void **priv,
CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
if (act == VDP_INIT)
return (0);
CAST_OBJ_NOTNULL(vrg_priv, *priv, VRG_PRIV_MAGIC);
if (act == VDP_FINI) {
*priv = NULL;
if (vrg_priv->range_off < vrg_priv->range_high)
SES_Close(req->sp, SC_RANGE_SHORT);
*priv = NULL; /* struct on ws, no need to free */
return (0);
}
CAST_OBJ_NOTNULL(vrg_priv, *priv, VRG_PRIV_MAGIC);
l = vrg_priv->range_low - vrg_priv->range_off;
if (l > 0) {
if (l > len)
......@@ -126,19 +129,29 @@ vrg_dorange(struct req *req, const struct busyobj *bo, ssize_t len,
return (__LINE__);
if (!has_low) {
if (bo != NULL)
return (0); // Allow 200 response
if (high == 0)
return (__LINE__);
low = len - high;
if (low < 0)
low = 0;
high = len - 1;
} else if (high >= len || !has_high)
} else if (bo == NULL && (high >= len || !has_high))
high = len - 1;
else if (!has_high)
return (0); // Allow 200 response
/*
* else (bo != NULL) {
* We assume that the client knows what it's doing and trust
* that both low and high make sense.
* }
*/
if (high < low)
return (__LINE__);
if (low >= len)
if (bo == NULL && low >= len)
return (__LINE__);
http_PrintfHeader(req->resp, "Content-Range: bytes %jd-%jd/%jd",
......
varnishtest "Streaming of C-L header from backend"
varnishtest "range requests on streamed response"
server s1 {
server s1 -repeat 4 {
rxreq
txresp -nolen -hdr "Content-Length: 020"
send "0123456789"
txresp -nolen \
-hdr "Transfer-Encoding: chunked" \
-hdr "Connection: close"
send "11\r\n0_23456789abcdef\n"
send "11\r\n1_23456789abcdef\n"
send "11\r\n2_23456789abcdef\n"
send "11\r\n3_23456789abcdef\n"
sema r1 sync 2
send "0123456789"
send "11\r\n4_23456789abcdef\n"
send "11\r\n5_23456789abcdef\n"
send "11\r\n6_23456789abcdef\n"
send "11\r\n7_23456789abcdef\n"
chunkedlen 0
rxreq
txresp -nolen -hdr "Content-Length: 010"
sema r2 sync 2
send "0123456789"
} -start
varnish v1 -vcl+backend {
varnish v1 -vcl+backend {} -start
varnish v1 -cliok "param.set debug +syncvsl"
sub vcl_backend_response {
if (bereq.url == "/2") {
set beresp.do_gzip = true;
}
}
} -start -cliok "param.set debug +syncvsl" -cliok "param.set debug +flush_head"
logexpect l1 -v v1 -g session {
expect 0 1000 Begin sess
expect * = SessClose RANGE_SHORT
} -start
client c1 {
txreq
txreq -url /1 -hdr "Range: bytes=17-101"
rxresphdrs
expect resp.status == 206
expect resp.http.content-length == 85
sema r1 sync 2
rxrespbody
expect resp.bodylen == 85
delay .1
# We cannot do tail-ranges when streaming
txreq -url /2 -hdr "Range: bytes=-10"
rxresphdrs
expect resp.http.content-length == "020"
expect resp.status == 200
expect resp.http.Transfer-Encoding == chunked
sema r1 sync 2
rxrespbody
expect resp.body == "01234567890123456789"
expect resp.bodylen == 136
delay .1
txreq -url "/2"
# We cannot do open-ranges when streaming
txreq -url /3 -hdr "Range: bytes=17-"
rxresphdrs
expect resp.http.content-length == "<undef>"
sema r2 sync 2
expect resp.status == 200
expect resp.http.Transfer-Encoding == chunked
sema r1 sync 2
rxrespbody
expect resp.body == "0123456789"
expect resp.bodylen == 136
delay .1
txreq -url "/2"
rxresp
expect resp.http.content-length == "10"
# Invalid range
txreq -url /4 -hdr "Range: bytes=102-200"
rxresphdrs
expect resp.status == 206
expect resp.http.content-length == 99
sema r1 sync 2
recv 34
delay .3
expect_close
} -run
varnish v1 -expect sc_range_short == 1
logexpect l1 -wait
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment