mirror of
https://github.com/curl/curl.git
synced 2024-11-21 01:16:58 +08:00
request: on shutdown send, proceed normally on timeout
When ending an FTP upload, we shut down the connection gracefully, since the server should be notified we had send all bytes. Mostly, this is a NOP without TLS involved. With TLS, close-notify messages should be exchanged. As reported in #14843, not all servers seem to do that. Since it is the server's responsiblity to check it has received everything, we just log the timeout and proceed as if everything is fine. In the receive direction, we still fail the transfer if the server does not shut down its direction properly. Fixes #14843 Reported-by: Rasmus Melchior Jacobsen Closes #14848
This commit is contained in:
parent
47d6ec9804
commit
b2331f3eea
@ -210,7 +210,8 @@ CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
|
||||
else {
|
||||
timeout_ms = Curl_shutdown_timeleft(data->conn, sockindex, &now);
|
||||
if(timeout_ms < 0) {
|
||||
failf(data, "SSL shutdown timeout");
|
||||
/* info message, since this might be regarded as acceptable */
|
||||
infof(data, "shutdown timeout");
|
||||
return CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
@ -653,12 +653,14 @@ static CURLcode InitiateTransfer(struct Curl_easy *data)
|
||||
/* set the SO_SNDBUF for the secondary socket for those who need it */
|
||||
Curl_sndbuf_init(conn->sock[SECONDARYSOCKET]);
|
||||
|
||||
Curl_xfer_setup2(data, CURL_XFER_SEND, -1, TRUE);
|
||||
/* FTP upload, shutdown DATA, ignore shutdown errors, as we rely
|
||||
* on the server response on the CONTROL connection. */
|
||||
Curl_xfer_setup2(data, CURL_XFER_SEND, -1, TRUE, TRUE);
|
||||
}
|
||||
else {
|
||||
/* FTP download: */
|
||||
/* FTP download, shutdown, do not ignore errors */
|
||||
Curl_xfer_setup2(data, CURL_XFER_RECV,
|
||||
conn->proto.ftpc.retr_size_saved, TRUE);
|
||||
conn->proto.ftpc.retr_size_saved, TRUE, FALSE);
|
||||
}
|
||||
|
||||
conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
|
||||
|
@ -327,6 +327,13 @@ static CURLcode req_flush(struct Curl_easy *data)
|
||||
if(data->req.shutdown) {
|
||||
bool done;
|
||||
result = Curl_xfer_send_shutdown(data, &done);
|
||||
if(result && data->req.shutdown_err_ignore) {
|
||||
infof(data, "Shutdown send direction error: %d. Broken server? "
|
||||
"Proceeding as if everything is ok.", result);
|
||||
result = CURLE_OK;
|
||||
done = TRUE;
|
||||
}
|
||||
|
||||
if(result)
|
||||
return result;
|
||||
if(!done)
|
||||
|
@ -151,6 +151,7 @@ struct SingleRequest {
|
||||
negotiation. */
|
||||
BIT(sendbuf_init); /* sendbuf is initialized */
|
||||
BIT(shutdown); /* request end will shutdown connection */
|
||||
BIT(shutdown_err_ignore); /* errors in shutdown will not fail request */
|
||||
#ifdef USE_HYPER
|
||||
BIT(bodywritten);
|
||||
#endif
|
||||
|
@ -1069,8 +1069,10 @@ static void xfer_setup(
|
||||
bool getheader, /* TRUE if header parsing is wanted */
|
||||
int writesockindex, /* socket index to write to, it may very well be
|
||||
the same we read from. -1 disables */
|
||||
bool shutdown /* shutdown connection at transfer end. Only
|
||||
bool shutdown, /* shutdown connection at transfer end. Only
|
||||
* supported when sending OR receiving. */
|
||||
bool shutdown_err_ignore /* errors during shutdown do not fail the
|
||||
* transfer */
|
||||
)
|
||||
{
|
||||
struct SingleRequest *k = &data->req;
|
||||
@ -1102,6 +1104,7 @@ static void xfer_setup(
|
||||
k->getheader = getheader;
|
||||
k->size = size;
|
||||
k->shutdown = shutdown;
|
||||
k->shutdown_err_ignore = shutdown_err_ignore;
|
||||
|
||||
/* The code sequence below is placed in this function just because all
|
||||
necessary input is not always known in do_complete() as this function may
|
||||
@ -1126,7 +1129,7 @@ static void xfer_setup(
|
||||
|
||||
void Curl_xfer_setup_nop(struct Curl_easy *data)
|
||||
{
|
||||
xfer_setup(data, -1, -1, FALSE, -1, FALSE);
|
||||
xfer_setup(data, -1, -1, FALSE, -1, FALSE, FALSE);
|
||||
}
|
||||
|
||||
void Curl_xfer_setup1(struct Curl_easy *data,
|
||||
@ -1137,18 +1140,20 @@ void Curl_xfer_setup1(struct Curl_easy *data,
|
||||
int recv_index = (send_recv & CURL_XFER_RECV) ? FIRSTSOCKET : -1;
|
||||
int send_index = (send_recv & CURL_XFER_SEND) ? FIRSTSOCKET : -1;
|
||||
DEBUGASSERT((recv_index >= 0) || (recv_size == -1));
|
||||
xfer_setup(data, recv_index, recv_size, getheader, send_index, FALSE);
|
||||
xfer_setup(data, recv_index, recv_size, getheader, send_index, FALSE, FALSE);
|
||||
}
|
||||
|
||||
void Curl_xfer_setup2(struct Curl_easy *data,
|
||||
int send_recv,
|
||||
curl_off_t recv_size,
|
||||
bool shutdown)
|
||||
bool shutdown,
|
||||
bool shutdown_err_ignore)
|
||||
{
|
||||
int recv_index = (send_recv & CURL_XFER_RECV) ? SECONDARYSOCKET : -1;
|
||||
int send_index = (send_recv & CURL_XFER_SEND) ? SECONDARYSOCKET : -1;
|
||||
DEBUGASSERT((recv_index >= 0) || (recv_size == -1));
|
||||
xfer_setup(data, recv_index, recv_size, FALSE, send_index, shutdown);
|
||||
xfer_setup(data, recv_index, recv_size, FALSE, send_index,
|
||||
shutdown, shutdown_err_ignore);
|
||||
}
|
||||
|
||||
CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
|
||||
|
@ -100,12 +100,13 @@ void Curl_xfer_setup1(struct Curl_easy *data,
|
||||
* the amount to receive or -1 if unknown. With `shutdown` being
|
||||
* set, the transfer is only allowed to either send OR receive
|
||||
* and the socket 2 connection will be shutdown at the end of
|
||||
* the transfer. An unclean shutdown will fail the transfer.
|
||||
* the transfer. An unclean shutdown will fail the transfer
|
||||
* unless `shutdown_err_ignore` is TRUE.
|
||||
*/
|
||||
void Curl_xfer_setup2(struct Curl_easy *data,
|
||||
int send_recv,
|
||||
curl_off_t recv_size,
|
||||
bool shutdown);
|
||||
bool shutdown, bool shutdown_err_ignore);
|
||||
|
||||
/**
|
||||
* Multi has set transfer to DONE. Last chance to trigger
|
||||
|
Loading…
Reference in New Issue
Block a user