summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/transfer.c
diff options
context:
space:
mode:
authordartraiden <wowemuh@gmail.com>2024-11-06 20:55:13 +0300
committerdartraiden <wowemuh@gmail.com>2024-11-06 21:41:16 +0300
commit5d2ecfef56e49a8e4bfad25a582ff1597987f717 (patch)
treecdb31e45b051830ecf50c74a84b8d2ac5aa6cfd9 /libs/libcurl/src/transfer.c
parent995e85e9e63553576fc285d937d4abbad369e7e4 (diff)
libcurl: update to 8.11.0
Diffstat (limited to 'libs/libcurl/src/transfer.c')
-rw-r--r--libs/libcurl/src/transfer.c340
1 files changed, 27 insertions, 313 deletions
diff --git a/libs/libcurl/src/transfer.c b/libs/libcurl/src/transfer.c
index 55f868a8ec..53b7b84496 100644
--- a/libs/libcurl/src/transfer.c
+++ b/libs/libcurl/src/transfer.c
@@ -79,7 +79,6 @@
#include "http2.h"
#include "mime.h"
#include "strcase.h"
-#include "urlapi-int.h"
#include "hsts.h"
#include "setopt.h"
#include "headers.h"
@@ -205,10 +204,10 @@ CURLcode Curl_xfer_send_shutdown(struct Curl_easy *data, bool *done)
* @param err error code in case of -1 return
* @return number of bytes read or -1 for error
*/
-static ssize_t Curl_xfer_recv_resp(struct Curl_easy *data,
- char *buf, size_t blen,
- bool eos_reliable,
- CURLcode *err)
+static ssize_t xfer_recv_resp(struct Curl_easy *data,
+ char *buf, size_t blen,
+ bool eos_reliable,
+ CURLcode *err)
{
ssize_t nread;
@@ -223,7 +222,7 @@ static ssize_t Curl_xfer_recv_resp(struct Curl_easy *data,
blen = (size_t)totalleft;
}
else if(xfer_recv_shutdown_started(data)) {
- /* we already reveived everything. Do not try more. */
+ /* we already received everything. Do not try more. */
blen = 0;
}
@@ -303,8 +302,7 @@ static CURLcode sendrecv_dl(struct Curl_easy *data,
bytestoread = (size_t)data->set.max_recv_speed;
}
- nread = Curl_xfer_recv_resp(data, buf, bytestoread,
- is_multiplex, &result);
+ nread = xfer_recv_resp(data, buf, bytestoread, is_multiplex, &result);
if(nread < 0) {
if(CURLE_AGAIN != result)
goto out; /* real error */
@@ -680,6 +678,9 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY;
}
+ if(data->set.str[STRING_USERNAME] ||
+ data->set.str[STRING_PASSWORD])
+ data->state.creds_from = CREDS_OPTION;
if(!result)
result = Curl_setstropt(&data->state.aptr.user,
data->set.str[STRING_USERNAME]);
@@ -700,298 +701,6 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
return result;
}
-/*
- * Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string
- * as given by the remote server and set up the new URL to request.
- *
- * This function DOES NOT FREE the given url.
- */
-CURLcode Curl_follow(struct Curl_easy *data,
- char *newurl, /* the Location: string */
- followtype type) /* see transfer.h */
-{
-#ifdef CURL_DISABLE_HTTP
- (void)data;
- (void)newurl;
- (void)type;
- /* Location: following will not happen when HTTP is disabled */
- return CURLE_TOO_MANY_REDIRECTS;
-#else
-
- /* Location: redirect */
- bool disallowport = FALSE;
- bool reachedmax = FALSE;
- CURLUcode uc;
-
- DEBUGASSERT(type != FOLLOW_NONE);
-
- if(type != FOLLOW_FAKE)
- data->state.requests++; /* count all real follows */
- if(type == FOLLOW_REDIR) {
- if((data->set.maxredirs != -1) &&
- (data->state.followlocation >= data->set.maxredirs)) {
- reachedmax = TRUE;
- type = FOLLOW_FAKE; /* switch to fake to store the would-be-redirected
- to URL */
- }
- else {
- data->state.followlocation++; /* count redirect-followings, including
- auth reloads */
-
- if(data->set.http_auto_referer) {
- CURLU *u;
- char *referer = NULL;
-
- /* We are asked to automatically set the previous URL as the referer
- when we get the next URL. We pick the ->url field, which may or may
- not be 100% correct */
-
- if(data->state.referer_alloc) {
- Curl_safefree(data->state.referer);
- data->state.referer_alloc = FALSE;
- }
-
- /* Make a copy of the URL without credentials and fragment */
- u = curl_url();
- if(!u)
- return CURLE_OUT_OF_MEMORY;
-
- uc = curl_url_set(u, CURLUPART_URL, data->state.url, 0);
- if(!uc)
- uc = curl_url_set(u, CURLUPART_FRAGMENT, NULL, 0);
- if(!uc)
- uc = curl_url_set(u, CURLUPART_USER, NULL, 0);
- if(!uc)
- uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0);
- if(!uc)
- uc = curl_url_get(u, CURLUPART_URL, &referer, 0);
-
- curl_url_cleanup(u);
-
- if(uc || !referer)
- return CURLE_OUT_OF_MEMORY;
-
- data->state.referer = referer;
- data->state.referer_alloc = TRUE; /* yes, free this later */
- }
- }
- }
-
- if((type != FOLLOW_RETRY) &&
- (data->req.httpcode != 401) && (data->req.httpcode != 407) &&
- Curl_is_absolute_url(newurl, NULL, 0, FALSE)) {
- /* If this is not redirect due to a 401 or 407 response and an absolute
- URL: do not allow a custom port number */
- disallowport = TRUE;
- }
-
- DEBUGASSERT(data->state.uh);
- uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, (unsigned int)
- ((type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME :
- ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) |
- CURLU_ALLOW_SPACE |
- (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)));
- if(uc) {
- if(type != FOLLOW_FAKE) {
- failf(data, "The redirect target URL could not be parsed: %s",
- curl_url_strerror(uc));
- return Curl_uc_to_curlcode(uc);
- }
-
- /* the URL could not be parsed for some reason, but since this is FAKE
- mode, just duplicate the field as-is */
- newurl = strdup(newurl);
- if(!newurl)
- return CURLE_OUT_OF_MEMORY;
- }
- else {
- uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0);
- if(uc)
- return Curl_uc_to_curlcode(uc);
-
- /* Clear auth if this redirects to a different port number or protocol,
- unless permitted */
- if(!data->set.allow_auth_to_other_hosts && (type != FOLLOW_FAKE)) {
- char *portnum;
- int port;
- bool clear = FALSE;
-
- if(data->set.use_port && data->state.allow_port)
- /* a custom port is used */
- port = (int)data->set.use_port;
- else {
- uc = curl_url_get(data->state.uh, CURLUPART_PORT, &portnum,
- CURLU_DEFAULT_PORT);
- if(uc) {
- free(newurl);
- return Curl_uc_to_curlcode(uc);
- }
- port = atoi(portnum);
- free(portnum);
- }
- if(port != data->info.conn_remote_port) {
- infof(data, "Clear auth, redirects to port from %u to %u",
- data->info.conn_remote_port, port);
- clear = TRUE;
- }
- else {
- char *scheme;
- const struct Curl_handler *p;
- uc = curl_url_get(data->state.uh, CURLUPART_SCHEME, &scheme, 0);
- if(uc) {
- free(newurl);
- return Curl_uc_to_curlcode(uc);
- }
-
- p = Curl_get_scheme_handler(scheme);
- if(p && (p->protocol != data->info.conn_protocol)) {
- infof(data, "Clear auth, redirects scheme from %s to %s",
- data->info.conn_scheme, scheme);
- clear = TRUE;
- }
- free(scheme);
- }
- if(clear) {
- Curl_safefree(data->state.aptr.user);
- Curl_safefree(data->state.aptr.passwd);
- }
- }
- }
-
- if(type == FOLLOW_FAKE) {
- /* we are only figuring out the new URL if we would have followed locations
- but now we are done so we can get out! */
- data->info.wouldredirect = newurl;
-
- if(reachedmax) {
- failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs);
- return CURLE_TOO_MANY_REDIRECTS;
- }
- return CURLE_OK;
- }
-
- if(disallowport)
- data->state.allow_port = FALSE;
-
- if(data->state.url_alloc)
- Curl_safefree(data->state.url);
-
- data->state.url = newurl;
- data->state.url_alloc = TRUE;
- Curl_req_soft_reset(&data->req, data);
- infof(data, "Issue another request to this URL: '%s'", data->state.url);
-
- /*
- * We get here when the HTTP code is 300-399 (and 401). We need to perform
- * differently based on exactly what return code there was.
- *
- * News from 7.10.6: we can also get here on a 401 or 407, in case we act on
- * an HTTP (proxy-) authentication scheme other than Basic.
- */
- switch(data->info.httpcode) {
- /* 401 - Act on a WWW-Authenticate, we keep on moving and do the
- Authorization: XXXX header in the HTTP request code snippet */
- /* 407 - Act on a Proxy-Authenticate, we keep on moving and do the
- Proxy-Authorization: XXXX header in the HTTP request code snippet */
- /* 300 - Multiple Choices */
- /* 306 - Not used */
- /* 307 - Temporary Redirect */
- default: /* for all above (and the unknown ones) */
- /* Some codes are explicitly mentioned since I have checked RFC2616 and
- * they seem to be OK to POST to.
- */
- break;
- case 301: /* Moved Permanently */
- /* (quote from RFC7231, section 6.4.2)
- *
- * Note: For historical reasons, a user agent MAY change the request
- * method from POST to GET for the subsequent request. If this
- * behavior is undesired, the 307 (Temporary Redirect) status code
- * can be used instead.
- *
- * ----
- *
- * Many webservers expect this, so these servers often answers to a POST
- * request with an error page. To be sure that libcurl gets the page that
- * most user agents would get, libcurl has to force GET.
- *
- * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and
- * can be overridden with CURLOPT_POSTREDIR.
- */
- if((data->state.httpreq == HTTPREQ_POST
- || data->state.httpreq == HTTPREQ_POST_FORM
- || data->state.httpreq == HTTPREQ_POST_MIME)
- && !(data->set.keep_post & CURL_REDIR_POST_301)) {
- infof(data, "Switch from POST to GET");
- data->state.httpreq = HTTPREQ_GET;
- Curl_creader_set_rewind(data, FALSE);
- }
- break;
- case 302: /* Found */
- /* (quote from RFC7231, section 6.4.3)
- *
- * Note: For historical reasons, a user agent MAY change the request
- * method from POST to GET for the subsequent request. If this
- * behavior is undesired, the 307 (Temporary Redirect) status code
- * can be used instead.
- *
- * ----
- *
- * Many webservers expect this, so these servers often answers to a POST
- * request with an error page. To be sure that libcurl gets the page that
- * most user agents would get, libcurl has to force GET.
- *
- * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and
- * can be overridden with CURLOPT_POSTREDIR.
- */
- if((data->state.httpreq == HTTPREQ_POST
- || data->state.httpreq == HTTPREQ_POST_FORM
- || data->state.httpreq == HTTPREQ_POST_MIME)
- && !(data->set.keep_post & CURL_REDIR_POST_302)) {
- infof(data, "Switch from POST to GET");
- data->state.httpreq = HTTPREQ_GET;
- Curl_creader_set_rewind(data, FALSE);
- }
- break;
-
- case 303: /* See Other */
- /* 'See Other' location is not the resource but a substitute for the
- * resource. In this case we switch the method to GET/HEAD, unless the
- * method is POST and the user specified to keep it as POST.
- * https://github.com/curl/curl/issues/5237#issuecomment-614641049
- */
- if(data->state.httpreq != HTTPREQ_GET &&
- ((data->state.httpreq != HTTPREQ_POST &&
- data->state.httpreq != HTTPREQ_POST_FORM &&
- data->state.httpreq != HTTPREQ_POST_MIME) ||
- !(data->set.keep_post & CURL_REDIR_POST_303))) {
- data->state.httpreq = HTTPREQ_GET;
- infof(data, "Switch to %s",
- data->req.no_body?"HEAD":"GET");
- }
- break;
- case 304: /* Not Modified */
- /* 304 means we did a conditional request and it was "Not modified".
- * We should not get any Location: header in this response!
- */
- break;
- case 305: /* Use Proxy */
- /* (quote from RFC2616, section 10.3.6):
- * "The requested resource MUST be accessed through the proxy given
- * by the Location field. The Location field gives the URI of the
- * proxy. The recipient is expected to repeat this single request
- * via the proxy. 305 responses MUST only be generated by origin
- * servers."
- */
- break;
- }
- Curl_pgrsTime(data, TIMER_REDIRECT);
- Curl_pgrsResetTransferSizes(data);
-
- return CURLE_OK;
-#endif /* CURL_DISABLE_HTTP */
-}
-
/* Returns CURLE_OK *and* sets '*url' if a request retry is wanted.
NOTE: that the *url is malloc()ed. */
@@ -1067,10 +776,12 @@ static void xfer_setup(
int sockindex, /* socket index to read from or -1 */
curl_off_t size, /* -1 if unknown at this point */
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
+ int writesockindex, /* socket index to write to, it may be the same we
+ read from. -1 disables */
+ 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;
@@ -1089,19 +800,20 @@ static void xfer_setup(
conn->sock[sockindex];
conn->writesockfd = conn->sockfd;
if(want_send)
- /* special and very HTTP-specific */
+ /* special and HTTP-specific */
writesockindex = FIRSTSOCKET;
}
else {
conn->sockfd = sockindex == -1 ?
CURL_SOCKET_BAD : conn->sock[sockindex];
conn->writesockfd = writesockindex == -1 ?
- CURL_SOCKET_BAD:conn->sock[writesockindex];
+ CURL_SOCKET_BAD : conn->sock[writesockindex];
}
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 +838,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,
@@ -1134,21 +846,23 @@ void Curl_xfer_setup1(struct Curl_easy *data,
curl_off_t recv_size,
bool getheader)
{
- int recv_index = (send_recv & CURL_XFER_RECV)? FIRSTSOCKET : -1;
- int send_index = (send_recv & CURL_XFER_SEND)? FIRSTSOCKET : -1;
+ 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;
+ 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,