diff --git a/docs/cmdline-opts/max-filesize.d b/docs/cmdline-opts/max-filesize.d index ada730d926..7541a27127 100644 --- a/docs/cmdline-opts/max-filesize.d +++ b/docs/cmdline-opts/max-filesize.d @@ -18,6 +18,9 @@ A size modifier may be used. For example, Appending 'k' or 'K' counts the number as kilobytes, 'm' or 'M' makes it megabytes, while 'g' or 'G' makes it gigabytes. Examples: 200K, 3m and 1G. (Added in 7.58.0) -**NOTE**: The file size is not always known prior to download, and for such -files this option has no effect even if the file transfer ends up being larger -than this given limit. +**NOTE**: before curl 8.4.0, when the file size is not known prior to +download, for such files this option has no effect even if the file transfer +ends up being larger than this given limit. + +Starting with curl 8.4.0, this option aborts the transfer if it reaches the +threshold during transfer. diff --git a/docs/libcurl/opts/CURLOPT_MAXFILESIZE.3 b/docs/libcurl/opts/CURLOPT_MAXFILESIZE.3 index f4b024047f..c1ff168693 100644 --- a/docs/libcurl/opts/CURLOPT_MAXFILESIZE.3 +++ b/docs/libcurl/opts/CURLOPT_MAXFILESIZE.3 @@ -41,6 +41,9 @@ transfers this option has no effect - even if the file transfer eventually ends up being larger than this given limit. If you want a limit above 2GB, use \fICURLOPT_MAXFILESIZE_LARGE(3)\fP. + +Since 8.4.0, this option also stops ongoing transfers if they reach this +threshold. .SH DEFAULT None .SH PROTOCOLS diff --git a/docs/libcurl/opts/CURLOPT_MAXFILESIZE_LARGE.3 b/docs/libcurl/opts/CURLOPT_MAXFILESIZE_LARGE.3 index 7e37fca92a..c40989e760 100644 --- a/docs/libcurl/opts/CURLOPT_MAXFILESIZE_LARGE.3 +++ b/docs/libcurl/opts/CURLOPT_MAXFILESIZE_LARGE.3 @@ -40,6 +40,9 @@ returned. The file size is not always known prior to the download start, and for such transfers this option has no effect - even if the file transfer eventually ends up being larger than this given limit. + +Since 8.4.0, this option also stops ongoing transfers if they reach this +threshold. .SH DEFAULT None .SH PROTOCOLS diff --git a/lib/c-hyper.c b/lib/c-hyper.c index 47dadfe4ce..c558955c9d 100644 --- a/lib/c-hyper.c +++ b/lib/c-hyper.c @@ -258,7 +258,11 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk) } data->req.bytecount += len; - Curl_pgrsSetDownloadCounter(data, data->req.bytecount); + result = Curl_pgrsSetDownloadCounter(data, data->req.bytecount); + if(result) { + data->state.hresult = result; + return HYPER_ITER_BREAK; + } return HYPER_ITER_CONTINUE; } diff --git a/lib/file.c b/lib/file.c index c751e8861a..ffa9fb76d0 100644 --- a/lib/file.c +++ b/lib/file.c @@ -571,7 +571,9 @@ static CURLcode file_do(struct Curl_easy *data, bool *done) if(result) return result; - Curl_pgrsSetDownloadCounter(data, bytecount); + result = Curl_pgrsSetDownloadCounter(data, bytecount); + if(result) + return result; if(Curl_pgrsUpdate(data)) result = CURLE_ABORTED_BY_CALLBACK; diff --git a/lib/ldap.c b/lib/ldap.c index 33a4dea0a8..239d3fbf01 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -735,7 +735,9 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) if(result) goto quit; dlsize++; - Curl_pgrsSetDownloadCounter(data, dlsize); + result = Curl_pgrsSetDownloadCounter(data, dlsize); + if(result) + goto quit; } if(ber) diff --git a/lib/mqtt.c b/lib/mqtt.c index eb53560f9a..5cb2d24110 100644 --- a/lib/mqtt.c +++ b/lib/mqtt.c @@ -668,7 +668,9 @@ MQTT_SUBACK_COMING: mq->npacket -= nread; k->bytecount += nread; - Curl_pgrsSetDownloadCounter(data, k->bytecount); + result = Curl_pgrsSetDownloadCounter(data, k->bytecount); + if(result) + goto end; /* if QoS is set, message contains packet id */ diff --git a/lib/progress.c b/lib/progress.c index 6092b782c7..e783a9c86d 100644 --- a/lib/progress.c +++ b/lib/progress.c @@ -317,9 +317,16 @@ timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize, /* * Set the number of downloaded bytes so far. */ -void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size) +CURLcode Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size) { + if(data->set.max_filesize && (size > data->set.max_filesize)) { + failf(data, "Exceeded the maximum allowed file size " + "(%" CURL_FORMAT_CURL_OFF_T ")", + data->set.max_filesize); + return CURLE_FILESIZE_EXCEEDED; + } data->progress.downloaded = size; + return CURLE_OK; } /* diff --git a/lib/progress.h b/lib/progress.h index 0049cd04be..fc39e34d20 100644 --- a/lib/progress.h +++ b/lib/progress.h @@ -46,7 +46,10 @@ int Curl_pgrsDone(struct Curl_easy *data); void Curl_pgrsStartNow(struct Curl_easy *data); void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size); void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size); -void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size); + +/* It is fine to not check the return code if 'size' is set to 0 */ +CURLcode Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size); + void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size); void Curl_ratelimit(struct Curl_easy *data, struct curltime now); int Curl_pgrsUpdate(struct Curl_easy *data); diff --git a/lib/smb.c b/lib/smb.c index afcc99de24..32c5137a44 100644 --- a/lib/smb.c +++ b/lib/smb.c @@ -1049,7 +1049,12 @@ static CURLcode smb_request_state(struct Curl_easy *data, bool *done) } data->req.bytecount += len; data->req.offset += len; - Curl_pgrsSetDownloadCounter(data, data->req.bytecount); + result = Curl_pgrsSetDownloadCounter(data, data->req.bytecount); + if(result) { + req->result = result; + next_state = SMB_CLOSE; + break; + } next_state = (len < MAX_PAYLOAD_SIZE) ? SMB_CLOSE : SMB_DOWNLOAD; break; diff --git a/lib/telnet.c b/lib/telnet.c index 850f88c1ec..836e255c9d 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -1570,8 +1570,9 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) } total_dl += nread; - Curl_pgrsSetDownloadCounter(data, total_dl); - result = telrcv(data, (unsigned char *)buf, nread); + result = Curl_pgrsSetDownloadCounter(data, total_dl); + if(!result) + result = telrcv(data, (unsigned char *)buf, nread); if(result) { keepon = FALSE; break; diff --git a/lib/tftp.c b/lib/tftp.c index 8ed1b887b4..e78140d520 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -1141,12 +1141,15 @@ static CURLcode tftp_receive_packet(struct Curl_easy *data) result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)state->rpacket.data + 4, state->rbytes-4); + if(!result) { + k->bytecount += state->rbytes-4; + result = Curl_pgrsSetDownloadCounter(data, + (curl_off_t) k->bytecount); + } if(result) { tftp_state_machine(state, TFTP_EVENT_ERROR); return result; } - k->bytecount += state->rbytes-4; - Curl_pgrsSetDownloadCounter(data, (curl_off_t) k->bytecount); } break; case TFTP_EVENT_ERROR: diff --git a/lib/transfer.c b/lib/transfer.c index d0602b8753..4c9ff0aa84 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -671,7 +671,9 @@ static CURLcode readwrite_data(struct Curl_easy *data, k->bytecount += nread; max_recv -= nread; - Curl_pgrsSetDownloadCounter(data, k->bytecount); + result = Curl_pgrsSetDownloadCounter(data, k->bytecount); + if(result) + goto out; if(!k->chunk && (nread || k->badheader || is_empty_data)) { /* If this is chunky transfer, it was already written */