Refactor range-parsing

Quark previously didn't really handle suffix-range-requests
(those of the form "-num", asking for the last num bytes) properly
and also did not catch the error when the lower in the range
"lower-upper" was actually larger than or equal to the size of the
requested file.

I always planned to refactor the parsing but got the motivation by
Eric Radman <ericshane@eradman.com>, who kindly reported the latter bug
to me.

Signed-off-by: Laslo Hunhold <dev@frign.de>
This commit is contained in:
Laslo Hunhold 2020-07-23 18:16:08 +02:00
parent 6b508a0e07
commit db4e35d3d5
No known key found for this signature in database
GPG key ID: 69576BD24CFCB980

79
http.c
View file

@ -562,18 +562,80 @@ http_send_response(int fd, struct request *r)
return http_send_status(fd, S_BAD_REQUEST); return http_send_status(fd, S_BAD_REQUEST);
} }
*(q++) = '\0'; *(q++) = '\0';
if (p[0]) {
/*
* byte-range=first\0last...
* ^ ^
* | |
* p q
*/
/*
* make sure we only have a single range,
* and not a comma separated list, which we
* will refuse to accept out of spite towards
* this horrible part of the spec
*/
if (strchr(q, ',')) {
goto not_satisfiable;
}
if (p[0] != '\0') {
/*
* Range has format "first-last" or "first-",
* i.e. return bytes 'first' to 'last' (or the
* last byte if 'last' is not given),
* inclusively, and byte-numbering beginning at 0
*/
lower = strtonum(p, 0, LLONG_MAX, &err); lower = strtonum(p, 0, LLONG_MAX, &err);
if (!err) {
if (q[0] != '\0') {
upper = strtonum(q, 0, LLONG_MAX,
&err);
} else {
upper = st.st_size - 1;
} }
if (!err && q[0]) { }
if (err) {
/* one of the strtonum()'s failed */
return http_send_status(fd, S_BAD_REQUEST);
}
/* check ranges */
if (lower > upper || lower >= st.st_size) {
goto not_satisfiable;
}
/* adjust upper limit to be at most the last byte */
upper = MIN(upper, st.st_size - 1);
} else {
/*
* Range has format "-num", i.e. return the 'num'
* last bytes
*/
/*
* use upper as a temporary storage for 'num',
* as we know 'upper' is st.st_size - 1
*/
upper = strtonum(q, 0, LLONG_MAX, &err); upper = strtonum(q, 0, LLONG_MAX, &err);
}
if (err) { if (err) {
return http_send_status(fd, S_BAD_REQUEST); return http_send_status(fd, S_BAD_REQUEST);
} }
/* check range */ /* determine lower */
if (lower < 0 || upper < 0 || lower > upper) { if (upper > st.st_size) {
/* more bytes requested than we have */
lower = 0;
} else {
lower = st.st_size - upper;
}
/* set upper to the correct value */
upper = st.st_size - 1;
}
goto satisfiable;
not_satisfiable:
if (dprintf(fd, if (dprintf(fd,
"HTTP/1.1 %d %s\r\n" "HTTP/1.1 %d %s\r\n"
"Date: %s\r\n" "Date: %s\r\n"
@ -587,11 +649,8 @@ http_send_response(int fd, struct request *r)
return S_REQUEST_TIMEOUT; return S_REQUEST_TIMEOUT;
} }
return S_RANGE_NOT_SATISFIABLE; return S_RANGE_NOT_SATISFIABLE;
} satisfiable:
;
/* adjust upper limit */
if (upper >= st.st_size)
upper = st.st_size-1;
} }
/* mime */ /* mime */