fetch: handle GET with offset == length.

While xbps_fetch_file() creates the .part file and for whatever reason
it did not finish properly to rename the file, it could request the server
to restart the download with offset set to file size, resulting in HTTP 416
return code.

Handle this case by checking if the server returns 416 and then checking
if the returned file size matches the requested offset and just rename
the file.

Thanks to @beefcurtains for the test case.
This commit is contained in:
Juan RP 2015-06-28 04:28:55 +02:00
parent bb5bfc37b3
commit 791e683e01
2 changed files with 12 additions and 6 deletions

View File

@ -173,6 +173,9 @@ xbps_fetch_file_dest(struct xbps_handle *xhp, const char *uri, const char *filen
if (fetchLastErrCode == FETCH_UNCHANGED) { if (fetchLastErrCode == FETCH_UNCHANGED) {
/* Last-Modified matched */ /* Last-Modified matched */
goto fetch_file_out; goto fetch_file_out;
} else if (fetchLastErrCode == FETCH_PROTO && url_st.size == stp->st_size) {
/* 413, requested offset == length */
goto rename_file;
} }
rv = -1; rv = -1;
goto fetch_file_out; goto fetch_file_out;
@ -257,6 +260,7 @@ xbps_fetch_file_dest(struct xbps_handle *xhp, const char *uri, const char *filen
*/ */
xbps_set_cb_fetch(xhp, url_st.size, url->offset, bytes_dload, xbps_set_cb_fetch(xhp, url_st.size, url->offset, bytes_dload,
filename, false, false, true); filename, false, false, true);
/* /*
* Update mtime in local file to match remote file if transfer * Update mtime in local file to match remote file if transfer
* was successful. * was successful.
@ -271,6 +275,7 @@ xbps_fetch_file_dest(struct xbps_handle *xhp, const char *uri, const char *filen
(void)close(fd); (void)close(fd);
fd = -1; fd = -1;
rename_file:
/* File downloaded successfully, rename to destfile */ /* File downloaded successfully, rename to destfile */
if (rename(tempfile, filename) == -1) { if (rename(tempfile, filename) == -1) {
xbps_dbg_printf(xhp, "failed to rename %s to %s: %s", xbps_dbg_printf(xhp, "failed to rename %s to %s: %s",

View File

@ -1133,6 +1133,12 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
goto ouch; goto ouch;
} }
/* fill in stats */
if (us) {
us->size = size;
us->atime = us->mtime = mtime;
}
/* check for inconsistencies */ /* check for inconsistencies */
if (clength != -1 && length != -1 && clength != length) { if (clength != -1 && length != -1 && clength != length) {
http_seterr(HTTP_PROTOCOL_ERROR); http_seterr(HTTP_PROTOCOL_ERROR);
@ -1142,6 +1148,7 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
clength = length; clength = length;
if (clength != -1) if (clength != -1)
length = offset + clength; length = offset + clength;
if (length != -1 && size != -1 && length != size) { if (length != -1 && size != -1 && length != size) {
http_seterr(HTTP_PROTOCOL_ERROR); http_seterr(HTTP_PROTOCOL_ERROR);
goto ouch; goto ouch;
@ -1149,12 +1156,6 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
if (size == -1) if (size == -1)
size = length; size = length;
/* fill in stats */
if (us) {
us->size = size;
us->atime = us->mtime = mtime;
}
/* too far? */ /* too far? */
if (URL->offset > 0 && offset > URL->offset) { if (URL->offset > 0 && offset > URL->offset) {
http_seterr(HTTP_PROTOCOL_ERROR); http_seterr(HTTP_PROTOCOL_ERROR);