Merge pull request #3 from darlinghq/update_sources_11.5

Update Sources 11.5 - curl
This commit is contained in:
CuriousTommy 2023-05-11 22:35:42 -07:00 committed by GitHub
commit 52c138f524
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 637 additions and 260 deletions

9
README.md Normal file
View File

@ -0,0 +1,9 @@
# darling-curl
## Upstream URL
https://github.com/apple-oss-distributions/curl/tree/curl-121.100.3
## Updating Source
When updating the source code, make sure to refer to the [`Updating Sources`](https://docs.darlinghq.org/contributing/updating-sources/index.html#updating-sources) section from the Darling Docs website. Additional details (if any) can be found in [`darling/notes/UPDATE_SOURCE.md`](darling/notes/UPDATE_SOURCE.md).

View File

@ -20,6 +20,13 @@
<string>lib/curl_gssapi.c: Address pointer alignment issue in gss_OID_desc structs.</string>
<string>include/curl/curl.h: Moved CURLE_SSL_CACERT back to being an enum value instead of a macro.</string>
<string>lib/vauth/spnego_gssapi.c: Replace OOM error with login denied error</string>
<string>Backport patches for CVE-2019-5435, CVE-2019-5436, CVE-2019-5481, CVE-2019-5482 (#58454021)</string>
<string>Backport patch for CVE-2020-8169 (#64715228)</string>
<string>Backport patch for CVE-2020-8177 (#64715230)</string>
<string>Backport patch for CVE-2020-8231 (#67490958)</string>
<string>Backport patch for CVE-2020-8284 (#71755686)</string>
<string>Backport patch for CVE-2020-8285 (#71830259)</string>
<string>Backport patch for CVE-2020-8286 (#71982292)</string>
</array>
<key>OpenSourceLicense</key>
<string>MIT</string>

View File

@ -9,4 +9,6 @@ to curl's PASV command when curl connects the data connection. Instead curl
will re-use the same IP address it already uses for the control
connection.
Since curl 7.74.0 this option is enabled by default.
This option has no effect if PORT, EPRT or EPSV is used instead of PASV.

View File

@ -273,9 +273,10 @@ as "pkcs11" if none was provided and the \fI--cert-type\fP option will be set as
"ENG" if none was provided.
(iOS and macOS only) If curl is built against Secure Transport, then the
certificate string can either be the name of a certificate/private key in the
system or user keychain, or the path to a PKCS#12-encoded certificate and
private key. If you want to use a file from the current directory, please
certificate string can either be the name or public key hash of a certificate/private
key in the system or user keychain, or the path to a PKCS#12-encoded certificate and
private key. A string beginning with "pkh/" will be interpreted as a
public key hash. If you want to use a file from the current directory, please
precede it with "./" prefix, in order to avoid confusion with a nickname.
(Schannel only) Client certificates must be specified by a path

View File

@ -5,7 +5,7 @@
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" *
.\" * This software is licensed as described in the file COPYING, which
.\" * you should have received as part of this distribution. The terms
@ -36,11 +36,13 @@ address it already uses for the control connection. But it will use the port
number from the 227-response.
This option thus allows libcurl to work around broken server installations
that due to NATs, firewalls or incompetence report the wrong IP address back.
that due to NATs, firewalls or incompetence report the wrong IP address
back. Setting the option also reduces the risk for various sorts of client
abuse by malicious servers.
This option has no effect if PORT, EPRT or EPSV is used instead of PASV.
.SH DEFAULT
0
1 since 7.74.0, was 0 before then.
.SH PROTOCOLS
FTP
.SH EXAMPLE

View File

@ -1228,15 +1228,15 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
}
struct connfind {
struct connectdata *tofind;
bool found;
long id_tofind;
struct connectdata *found;
};
static int conn_is_conn(struct connectdata *conn, void *param)
{
struct connfind *f = (struct connfind *)param;
if(conn == f->tofind) {
f->found = TRUE;
if(conn->connection_id == f->id_tofind) {
f->found = conn;
return 1;
}
return 0;
@ -1258,21 +1258,22 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
* - that is associated with a multi handle, and whose connection
* was detached with CURLOPT_CONNECT_ONLY
*/
if(data->state.lastconnect && (data->multi_easy || data->multi)) {
struct connectdata *c = data->state.lastconnect;
if((data->state.lastconnect_id != -1) && (data->multi_easy || data->multi)) {
struct connectdata *c;
struct connfind find;
find.tofind = data->state.lastconnect;
find.found = FALSE;
find.id_tofind = data->state.lastconnect_id;
find.found = NULL;
Curl_conncache_foreach(data, data->multi_easy?
&data->multi_easy->conn_cache:
&data->multi->conn_cache, &find, conn_is_conn);
if(!find.found) {
data->state.lastconnect = NULL;
data->state.lastconnect_id = -1;
return CURL_SOCKET_BAD;
}
c = find.found;
if(connp) {
/* only store this if the caller cares for it */
*connp = c;

View File

@ -860,7 +860,7 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
/* the connection cache is setup on demand */
outcurl->state.conn_cache = NULL;
outcurl->state.lastconnect = NULL;
outcurl->state.lastconnect_id = -1;
outcurl->progress.flags = data->progress.flags;
outcurl->progress.callback = data->progress.callback;

View File

@ -3783,129 +3783,131 @@ static CURLcode init_wc_data(struct connectdata *conn)
return result;
}
/* This is called recursively */
static CURLcode wc_statemach(struct connectdata *conn)
{
struct WildcardData * const wildcard = &(conn->data->wildcard);
CURLcode result = CURLE_OK;
switch(wildcard->state) {
case CURLWC_INIT:
result = init_wc_data(conn);
if(wildcard->state == CURLWC_CLEAN)
/* only listing! */
break;
wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
break;
case CURLWC_MATCHING: {
/* In this state is LIST response successfully parsed, so lets restore
previous WRITEFUNCTION callback and WRITEDATA pointer */
struct ftp_wc *ftpwc = wildcard->protdata;
conn->data->set.fwrite_func = ftpwc->backup.write_function;
conn->data->set.out = ftpwc->backup.file_descriptor;
ftpwc->backup.write_function = ZERO_NULL;
ftpwc->backup.file_descriptor = NULL;
wildcard->state = CURLWC_DOWNLOADING;
if(Curl_ftp_parselist_geterror(ftpwc->parser)) {
/* error found in LIST parsing */
wildcard->state = CURLWC_CLEAN;
return wc_statemach(conn);
}
if(wildcard->filelist.size == 0) {
/* no corresponding file */
wildcard->state = CURLWC_CLEAN;
return CURLE_REMOTE_FILE_NOT_FOUND;
}
return wc_statemach(conn);
}
case CURLWC_DOWNLOADING: {
/* filelist has at least one file, lets get first one */
struct ftp_conn *ftpc = &conn->proto.ftpc;
struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
struct FTP *ftp = conn->data->req.protop;
char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
if(!tmp_path)
return CURLE_OUT_OF_MEMORY;
/* switch default ftp->path and tmp_path */
free(ftp->pathalloc);
ftp->pathalloc = ftp->path = tmp_path;
infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
if(conn->data->set.chunk_bgn) {
long userresponse;
Curl_set_in_callback(conn->data, true);
userresponse = conn->data->set.chunk_bgn(
finfo, wildcard->customptr, (int)wildcard->filelist.size);
Curl_set_in_callback(conn->data, false);
switch(userresponse) {
case CURL_CHUNK_BGN_FUNC_SKIP:
infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
finfo->filename);
wildcard->state = CURLWC_SKIP;
return wc_statemach(conn);
case CURL_CHUNK_BGN_FUNC_FAIL:
return CURLE_CHUNK_FAILED;
}
}
if(finfo->filetype != CURLFILETYPE_FILE) {
wildcard->state = CURLWC_SKIP;
return wc_statemach(conn);
}
if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
ftpc->known_filesize = finfo->size;
result = ftp_parse_url_path(conn);
if(result)
for(;;) {
switch(wildcard->state) {
case CURLWC_INIT:
result = init_wc_data(conn);
if(wildcard->state == CURLWC_CLEAN)
/* only listing! */
return result;
wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
return result;
/* we don't need the Curl_fileinfo of first file anymore */
Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
case CURLWC_MATCHING: {
/* In this state is LIST response successfully parsed, so lets restore
previous WRITEFUNCTION callback and WRITEDATA pointer */
struct ftp_wc *ftpwc = wildcard->protdata;
conn->data->set.fwrite_func = ftpwc->backup.write_function;
conn->data->set.out = ftpwc->backup.file_descriptor;
ftpwc->backup.write_function = ZERO_NULL;
ftpwc->backup.file_descriptor = NULL;
wildcard->state = CURLWC_DOWNLOADING;
if(wildcard->filelist.size == 0) { /* remains only one file to down. */
wildcard->state = CURLWC_CLEAN;
/* after that will be ftp_do called once again and no transfer
will be done because of CURLWC_CLEAN state */
return CURLE_OK;
if(Curl_ftp_parselist_geterror(ftpwc->parser)) {
/* error found in LIST parsing */
wildcard->state = CURLWC_CLEAN;
continue;
}
if(wildcard->filelist.size == 0) {
/* no corresponding file */
wildcard->state = CURLWC_CLEAN;
return CURLE_REMOTE_FILE_NOT_FOUND;
}
continue;
}
} break;
case CURLWC_SKIP: {
if(conn->data->set.chunk_end) {
Curl_set_in_callback(conn->data, true);
conn->data->set.chunk_end(conn->data->wildcard.customptr);
Curl_set_in_callback(conn->data, false);
case CURLWC_DOWNLOADING: {
/* filelist has at least one file, lets get first one */
struct ftp_conn *ftpc = &conn->proto.ftpc;
struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
struct FTP *ftp = conn->data->req.protop;
char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
if(!tmp_path)
return CURLE_OUT_OF_MEMORY;
/* switch default ftp->path and tmp_path */
free(ftp->pathalloc);
ftp->pathalloc = ftp->path = tmp_path;
infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
if(conn->data->set.chunk_bgn) {
long userresponse;
Curl_set_in_callback(conn->data, true);
userresponse = conn->data->set.chunk_bgn(
finfo, wildcard->customptr, (int)wildcard->filelist.size);
Curl_set_in_callback(conn->data, false);
switch(userresponse) {
case CURL_CHUNK_BGN_FUNC_SKIP:
infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
finfo->filename);
wildcard->state = CURLWC_SKIP;
continue;
case CURL_CHUNK_BGN_FUNC_FAIL:
return CURLE_CHUNK_FAILED;
}
}
if(finfo->filetype != CURLFILETYPE_FILE) {
wildcard->state = CURLWC_SKIP;
continue;
}
if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
ftpc->known_filesize = finfo->size;
result = ftp_parse_url_path(conn);
if(result)
return result;
/* we don't need the Curl_fileinfo of first file anymore */
Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
if(wildcard->filelist.size == 0) { /* remains only one file to down. */
wildcard->state = CURLWC_CLEAN;
/* after that will be ftp_do called once again and no transfer
will be done because of CURLWC_CLEAN state */
return CURLE_OK;
}
return result;
}
case CURLWC_SKIP: {
if(conn->data->set.chunk_end) {
Curl_set_in_callback(conn->data, true);
conn->data->set.chunk_end(conn->data->wildcard.customptr);
Curl_set_in_callback(conn->data, false);
}
Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
wildcard->state = (wildcard->filelist.size == 0) ?
CURLWC_CLEAN : CURLWC_DOWNLOADING;
continue;
}
case CURLWC_CLEAN: {
struct ftp_wc *ftpwc = wildcard->protdata;
result = CURLE_OK;
if(ftpwc)
result = Curl_ftp_parselist_geterror(ftpwc->parser);
wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
return result;
}
case CURLWC_DONE:
case CURLWC_ERROR:
case CURLWC_CLEAR:
if(wildcard->dtor)
wildcard->dtor(wildcard->protdata);
return result;
}
Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
wildcard->state = (wildcard->filelist.size == 0) ?
CURLWC_CLEAN : CURLWC_DOWNLOADING;
return wc_statemach(conn);
}
case CURLWC_CLEAN: {
struct ftp_wc *ftpwc = wildcard->protdata;
result = CURLE_OK;
if(ftpwc)
result = Curl_ftp_parselist_geterror(ftpwc->parser);
wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
} break;
case CURLWC_DONE:
case CURLWC_ERROR:
case CURLWC_CLEAR:
if(wildcard->dtor)
wildcard->dtor(wildcard->protdata);
break;
}
return result;
/* UNREACHABLE */
}
/***********************************************************************

View File

@ -431,6 +431,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
data->state.conn_cache = &data->share->conn_cache;
else
data->state.conn_cache = &multi->conn_cache;
data->state.lastconnect_id = -1;
#ifdef USE_LIBPSL
/* Do the same for PSL. */
@ -645,11 +646,11 @@ static CURLcode multi_done(struct Curl_easy *data,
/* the connection is no longer in use by this transfer */
if(Curl_conncache_return_conn(conn)) {
/* remember the most recently used connection */
data->state.lastconnect = conn;
data->state.lastconnect_id = conn->connection_id;
infof(data, "%s\n", buffer);
}
else
data->state.lastconnect = NULL;
data->state.lastconnect_id = -1;
}
detach_connnection(data);

View File

@ -193,7 +193,6 @@ static CURLcode read_data(struct connectdata *conn,
struct krb5buffer *buf)
{
int len;
void *tmp = NULL;
CURLcode result;
result = socket_read(fd, &len, sizeof(len));
@ -203,12 +202,11 @@ static CURLcode read_data(struct connectdata *conn,
if(len) {
/* only realloc if there was a length */
len = ntohl(len);
tmp = Curl_saferealloc(buf->data, len);
buf->data = Curl_saferealloc(buf->data, len);
}
if(tmp == NULL)
if(!len || !buf->data)
return CURLE_OUT_OF_MEMORY;
buf->data = tmp;
result = socket_read(fd, buf->data, len);
if(result)
return result;

View File

@ -61,6 +61,13 @@ CURLcode Curl_setstropt(char **charp, const char *s)
if(s) {
char *str = strdup(s);
if(str) {
size_t len = strlen(str);
if(len > CURL_MAX_INPUT_LENGTH) {
free(str);
return CURLE_BAD_FUNCTION_ARGUMENT;
}
}
if(!str)
return CURLE_OUT_OF_MEMORY;

View File

@ -973,6 +973,7 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
{
tftp_state_data_t *state;
int blksize;
int need_blksize;
blksize = TFTP_BLKSIZE_DEFAULT;
@ -987,15 +988,20 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
return CURLE_TFTP_ILLEGAL;
}
need_blksize = blksize;
/* default size is the fallback when no OACK is received */
if(need_blksize < TFTP_BLKSIZE_DEFAULT)
need_blksize = TFTP_BLKSIZE_DEFAULT;
if(!state->rpacket.data) {
state->rpacket.data = calloc(1, blksize + 2 + 2);
state->rpacket.data = calloc(1, need_blksize + 2 + 2);
if(!state->rpacket.data)
return CURLE_OUT_OF_MEMORY;
}
if(!state->spacket.data) {
state->spacket.data = calloc(1, blksize + 2 + 2);
state->spacket.data = calloc(1, need_blksize + 2 + 2);
if(!state->spacket.data)
return CURLE_OUT_OF_MEMORY;
@ -1009,7 +1015,7 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
state->sockfd = state->conn->sock[FIRSTSOCKET];
state->state = TFTP_STATE_START;
state->error = TFTP_ERR_NONE;
state->blksize = TFTP_BLKSIZE_DEFAULT;
state->blksize = TFTP_BLKSIZE_DEFAULT; /* Unless updated by OACK response */
state->requested_blksize = blksize;
((struct sockaddr *)&state->local_addr)->sa_family =

View File

@ -444,6 +444,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */
set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */
set->ftp_filemethod = FTPFILE_MULTICWD;
set->ftp_skip_ip = TRUE; /* skip PASV IP by default */
set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
@ -606,7 +607,7 @@ CURLcode Curl_open(struct Curl_easy **curl)
Curl_initinfo(data);
/* most recent connection is not yet defined */
data->state.lastconnect = NULL;
data->state.lastconnect_id = -1;
data->progress.flags |= PGRS_HIDE;
data->state.current_speed = -1; /* init to negative == impossible */
@ -3111,12 +3112,14 @@ static CURLcode override_login(struct Curl_easy *data,
/* for updated strings, we update them in the URL */
if(user_changed) {
uc = curl_url_set(data->state.uh, CURLUPART_USER, *userp, 0);
uc = curl_url_set(data->state.uh, CURLUPART_USER, *userp,
CURLU_URLENCODE);
if(uc)
return Curl_uc_to_curlcode(uc);
}
if(passwd_changed) {
uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, *passwdp, 0);
uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, *passwdp,
CURLU_URLENCODE);
if(uc)
return Curl_uc_to_curlcode(uc);
}

View File

@ -642,6 +642,10 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
************************************************************/
/* allocate scratch area */
urllen = strlen(url);
if(urllen > CURL_MAX_INPUT_LENGTH)
/* excessive input length */
return CURLUE_MALFORMED_INPUT;
path = u->scratch = malloc(urllen * 2 + 2);
if(!path)
return CURLUE_OUT_OF_MEMORY;
@ -1272,6 +1276,10 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
const char *newp = part;
size_t nalloc = strlen(part);
if(nalloc > CURL_MAX_INPUT_LENGTH)
/* excessive input length */
return CURLUE_MALFORMED_INPUT;
if(urlencode) {
const char *i;
char *o;

View File

@ -79,6 +79,10 @@
*/
#define RESP_TIMEOUT (120*1000)
/* Max string intput length is a precaution against abuse and to detect junk
input easier and better. */
#define CURL_MAX_INPUT_LENGTH 8000000
#include "cookie.h"
#include "psl.h"
#include "formdata.h"
@ -1256,7 +1260,7 @@ struct UrlState {
/* buffers to store authentication data in, as parsed from input options */
struct curltime keeps_speed; /* for the progress meter really */
struct connectdata *lastconnect; /* The last connection, NULL if undefined */
long lastconnect_id; /* The last connection, -1 if undefined */
char *headerbuff; /* allocated buffer to store headers in */
size_t headersize; /* size of the allocation */

View File

@ -1732,6 +1732,11 @@ static CURLcode verifystatus(struct connectdata *conn,
OCSP_BASICRESP *br = NULL;
X509_STORE *st = NULL;
STACK_OF(X509) *ch = NULL;
X509 *cert;
OCSP_CERTID *id = NULL;
int cert_status, crl_reason;
ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
int ret;
long len = SSL_get_tlsext_status_ocsp_resp(BACKEND->handle, &status);
@ -1800,43 +1805,63 @@ static CURLcode verifystatus(struct connectdata *conn,
goto end;
}
for(i = 0; i < OCSP_resp_count(br); i++) {
int cert_status, crl_reason;
OCSP_SINGLERESP *single = NULL;
/* Compute the certificate's ID */
cert = SSL_get_peer_certificate(BACKEND->handle);
if(!cert) {
failf(data, "Error getting peer certficate");
result = CURLE_SSL_INVALIDCERTSTATUS;
goto end;
}
ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
single = OCSP_resp_get0(br, i);
if(!single)
continue;
cert_status = OCSP_single_get0_status(single, &crl_reason, &rev,
&thisupd, &nextupd);
if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) {
failf(data, "OCSP response has expired");
result = CURLE_SSL_INVALIDCERTSTATUS;
goto end;
for(i = 0; i < sk_X509_num(ch); i++) {
X509 *issuer = sk_X509_value(ch, i);
if(X509_check_issued(issuer, cert) == X509_V_OK) {
id = OCSP_cert_to_id(EVP_sha1(), cert, issuer);
break;
}
}
X509_free(cert);
infof(data, "SSL certificate status: %s (%d)\n",
OCSP_cert_status_str(cert_status), cert_status);
if(!id) {
failf(data, "Error computing OCSP ID");
result = CURLE_SSL_INVALIDCERTSTATUS;
goto end;
}
switch(cert_status) {
case V_OCSP_CERTSTATUS_GOOD:
break;
/* Find the single OCSP response corresponding to the certificate ID */
ret = OCSP_resp_find_status(br, id, &cert_status, &crl_reason, &rev,
&thisupd, &nextupd);
OCSP_CERTID_free(id);
if(ret != 1) {
failf(data, "Could not find certificate ID in OCSP response");
result = CURLE_SSL_INVALIDCERTSTATUS;
goto end;
}
case V_OCSP_CERTSTATUS_REVOKED:
result = CURLE_SSL_INVALIDCERTSTATUS;
/* Validate the corresponding single OCSP response */
if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) {
failf(data, "OCSP response has expired");
result = CURLE_SSL_INVALIDCERTSTATUS;
goto end;
}
failf(data, "SSL certificate revocation reason: %s (%d)",
OCSP_crl_reason_str(crl_reason), crl_reason);
goto end;
infof(data, "SSL certificate status: %s (%d)\n",
OCSP_cert_status_str(cert_status), cert_status);
case V_OCSP_CERTSTATUS_UNKNOWN:
result = CURLE_SSL_INVALIDCERTSTATUS;
goto end;
}
switch(cert_status) {
case V_OCSP_CERTSTATUS_GOOD:
break;
case V_OCSP_CERTSTATUS_REVOKED:
result = CURLE_SSL_INVALIDCERTSTATUS;
failf(data, "SSL certificate revocation reason: %s (%d)",
OCSP_crl_reason_str(crl_reason), crl_reason);
goto end;
case V_OCSP_CERTSTATUS_UNKNOWN:
default:
result = CURLE_SSL_INVALIDCERTSTATUS;
goto end;
}
end:

View File

@ -36,6 +36,7 @@
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
#endif /* __clang__ */
@ -1029,86 +1030,179 @@ static OSStatus CopyIdentityWithLabelOldSchool(char *label,
}
#endif /* CURL_SUPPORT_MAC_10_6 */
#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
static CFDataRef hexStrToData(CFStringRef hexStr) {
if(CFStringGetLength(hexStr) % 2 != 0)
return NULL;
char buffer[128];
const char *hexStrPtr = CFStringGetCStringPtr(hexStr, kCFStringEncodingUTF8);
if(hexStrPtr == NULL) {
bool res = CFStringGetCString(hexStr, buffer, sizeof(buffer),
kCFStringEncodingUTF8);
if(res)
hexStrPtr = buffer;
else
return NULL;
}
CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
if(data != NULL) {
CFDataSetLength(data, CFStringGetLength(hexStr) / 2);
UInt8 *dataPtr = CFDataGetMutableBytePtr(data);
char tmpByteChars[3] = {0, 0, 0};
for(int i = 0; i < CFDataGetLength(data); ++i) {
tmpByteChars[0] = hexStrPtr[i * 2];
tmpByteChars[1] = hexStrPtr[i * 2 + 1];
dataPtr[i] = (UInt8)strtol(tmpByteChars, NULL, 16);
}
}
return data;
}
static OSStatus CopyIdentityWithPubKeyHash(CFDataRef pubKeyHash,
SecIdentityRef *out_cert_and_key) {
OSStatus status = errSecItemNotFound;
CFArrayRef identities = NULL;
SecPolicyRef policy = NULL;
CFMutableDictionaryRef query =
CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if(query == NULL)
goto end;
policy = SecPolicyCreateSSL(false, NULL);
if(policy == NULL)
goto end;
CFDictionarySetValue(query, kSecClass, kSecClassIdentity);
CFDictionarySetValue(query, kSecAttrApplicationLabel, pubKeyHash);
CFDictionarySetValue(query, kSecMatchPolicy, policy);
CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
CFDictionarySetValue(query, kSecReturnAttributes, kCFBooleanTrue);
status = SecItemCopyMatching(query, (CFTypeRef *)&identities);
if(status != errSecSuccess)
goto end;
status = errSecItemNotFound;
for(int i = 0; i < CFArrayGetCount(identities); ++i) {
CFDictionaryRef attrs = CFArrayGetValueAtIndex(identities, i);
bool match = CFEqual(pubKeyHash,
CFDictionaryGetValue(attrs, kSecAttrPublicKeyHash));
if(match) {
if(out_cert_and_key != NULL)
*out_cert_and_key =
(SecIdentityRef)CFRetain(CFDictionaryGetValue(attrs, kSecValueRef));
status = errSecSuccess;
break;
}
}
end:
if(identities != NULL)
CFRelease(identities);
if(query != NULL)
CFRelease(query);
if(policy != NULL)
CFRelease(policy);
return status;
}
static OSStatus _CopyIdentityWithLabel(CFStringRef label,
SecIdentityRef *out_cert_and_key) {
OSStatus status = errSecItemNotFound;
SecPolicyRef policy = NULL;
CFArrayRef certs = NULL;
CFMutableDictionaryRef query =
CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if(query == NULL)
goto end;
policy = SecPolicyCreateSSL(false, NULL);
if(policy == NULL)
goto end;
CFDictionarySetValue(query, kSecClass, kSecClassIdentity);
CFDictionarySetValue(query, kSecAttrLabel, label);
CFDictionarySetValue(query, kSecMatchPolicy, policy);
CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
CFDictionarySetValue(query, kSecReturnAttributes, kCFBooleanTrue);
CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
status = SecItemCopyMatching(query, (CFTypeRef *)&certs);
if(status != errSecSuccess)
goto end;
status = errSecItemNotFound;
for(int i = 0; i < CFArrayGetCount(certs); ++i) {
CFDictionaryRef attrs = CFArrayGetValueAtIndex(certs, i);
CFComparisonResult match =
CFStringCompare(label, CFDictionaryGetValue(attrs, kSecAttrLabel), 0);
if(match == kCFCompareEqualTo) {
if(out_cert_and_key != NULL)
*out_cert_and_key =
(SecIdentityRef)CFRetain(CFDictionaryGetValue(attrs, kSecValueRef));
status = errSecSuccess;
break;
}
}
end:
if(certs != NULL)
CFRelease(certs);
if(query != NULL)
CFRelease(query);
if(policy != NULL)
CFRelease(policy);
return status;
}
#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
static OSStatus CopyIdentityWithLabel(char *label,
SecIdentityRef *out_cert_and_key)
{
OSStatus status = errSecItemNotFound;
#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
CFArrayRef keys_list;
CFIndex keys_list_count;
CFIndex i;
CFStringRef common_name;
static const CFStringRef publicKeyHashPrefix = CFSTR("pkh/");
long publicKeyHashPrefixLength = CFStringGetLength(publicKeyHashPrefix);
/* SecItemCopyMatching() was introduced in iOS and Snow Leopard.
kSecClassIdentity was introduced in Lion. If both exist, let's use them
to find the certificate. */
if(SecItemCopyMatching != NULL && kSecClassIdentity != NULL) {
CFTypeRef keys[5];
CFTypeRef values[5];
CFDictionaryRef query_dict;
CFStringRef label_cf = CFStringCreateWithCString(NULL, label,
kCFStringEncodingUTF8);
CFStringRef cfLabel = CFStringCreateWithCString(NULL, label,
kCFStringEncodingUTF8);
if(cfLabel == NULL)
goto end;
/* Set up our search criteria and expected results: */
values[0] = kSecClassIdentity; /* we want a certificate and a key */
keys[0] = kSecClass;
values[1] = kCFBooleanTrue; /* we want a reference */
keys[1] = kSecReturnRef;
values[2] = kSecMatchLimitAll; /* kSecMatchLimitOne would be better if the
* label matching below worked correctly */
keys[2] = kSecMatchLimit;
/* identity searches need a SecPolicyRef in order to work */
values[3] = SecPolicyCreateSSL(false, NULL);
keys[3] = kSecMatchPolicy;
/* match the name of the certificate (doesn't work in macOS 10.12.1) */
values[4] = label_cf;
keys[4] = kSecAttrLabel;
query_dict = CFDictionaryCreate(NULL, (const void **)keys,
(const void **)values, 5L,
&kCFCopyStringDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFRelease(values[3]);
if(CFStringHasPrefix(cfLabel, publicKeyHashPrefix)) {
CFRange pubKeyHashRange =
CFRangeMake(publicKeyHashPrefixLength,
CFStringGetLength(cfLabel) - publicKeyHashPrefixLength);
CFStringRef publicKeyHashStr =
CFStringCreateWithSubstring(NULL, cfLabel, pubKeyHashRange);
if(publicKeyHashStr != NULL) {
CFDataRef pubKeyHashData = hexStrToData(publicKeyHashStr);
if(pubKeyHashData != NULL) {
status = CopyIdentityWithPubKeyHash(pubKeyHashData, out_cert_and_key);
CFRelease(pubKeyHashData);
}
/* Do we have a match? */
status = SecItemCopyMatching(query_dict, (CFTypeRef *) &keys_list);
/* Because kSecAttrLabel matching doesn't work with kSecClassIdentity,
* we need to find the correct identity ourselves */
if(status == noErr) {
keys_list_count = CFArrayGetCount(keys_list);
*out_cert_and_key = NULL;
status = 1;
for(i = 0; i<keys_list_count; i++) {
OSStatus err = noErr;
SecCertificateRef cert = NULL;
SecIdentityRef identity =
(SecIdentityRef) CFArrayGetValueAtIndex(keys_list, i);
err = SecIdentityCopyCertificate(identity, &cert);
if(err == noErr) {
#if CURL_BUILD_IOS
common_name = SecCertificateCopySubjectSummary(cert);
#elif CURL_BUILD_MAC_10_7
SecCertificateCopyCommonName(cert, &common_name);
#endif
if(CFStringCompare(common_name, label_cf, 0) == kCFCompareEqualTo) {
CFRelease(cert);
CFRelease(common_name);
CFRetain(identity);
*out_cert_and_key = identity;
status = noErr;
break;
}
CFRelease(common_name);
}
CFRelease(cert);
CFRelease(publicKeyHashStr);
}
}
if(keys_list)
CFRelease(keys_list);
CFRelease(query_dict);
CFRelease(label_cf);
else {
status = _CopyIdentityWithLabel(cfLabel, out_cert_and_key);
}
CFRelease(cfLabel);
}
else {
#if CURL_SUPPORT_MAC_10_6
@ -1121,6 +1215,8 @@ static OSStatus CopyIdentityWithLabel(char *label,
to SecKeychainSearch. */
status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key);
#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
end:
return status;
}

View File

@ -132,25 +132,11 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
filename = parse_filename(p, len);
if(filename) {
if(outs->stream) {
int rc;
/* already opened and possibly written to */
if(outs->fopened)
fclose(outs->stream);
outs->stream = NULL;
/* rename the initial file name to the new file name */
rc = rename(outs->filename, filename);
if(rc != 0) {
warnf(outs->config->global, "Failed to rename %s -> %s: %s\n",
outs->filename, filename, strerror(errno));
}
if(outs->alloc_filename)
Curl_safefree(outs->filename);
if(rc != 0) {
/* indication of problem, get out! */
free(filename);
return failure;
}
}
outs->is_cd_filename = TRUE;
outs->s_isreg = TRUE;
outs->fopened = FALSE;

View File

@ -44,6 +44,7 @@ void config_init(struct OperationConfig* config)
config->tcp_nodelay = TRUE; /* enabled by default */
config->happy_eyeballs_timeout_ms = CURL_HET_DEFAULT;
config->http09_allowed = TRUE;
config->ftp_skip_ip = TRUE;
}
static void free_config_fields(struct OperationConfig *config)

View File

@ -1767,6 +1767,11 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
}
break;
case 'i':
if(config->content_disposition) {
warnf(global,
"--include and --remote-header-name cannot be combined.\n");
return PARAM_BAD_USE;
}
config->show_headers = toggle; /* show the headers as well in the
general output stream */
break;

View File

@ -363,10 +363,12 @@ void hugehelp(void)
" set as \"ENG\" if none was provided.\n"
"\n"
" (iOS and macOS only) If curl is built against Secure Transport,\n"
" then the certificate string can either be the name of a certifi-\n"
" cate/private key in the system or user keychain, or the path to\n"
" a PKCS#12-encoded certificate and private key. If you want to\n"
" use a file from the current directory, please precede it with\n"
" then the certificate string can either be the name or public key\n"
" hash of a certificate/private key in the system or user keychain,\n"
" or the path to a PKCS#12-encoded certificate and private key.\n"
" A string beginning with \"pkh/\" will be interpreted as a public key\n"
" hash. If you want to use a file from the current directory,\n"
" please precede it with\n"
, stdout);
fputs(
" \"./\" prefix, in order to avoid confusion with a nickname.\n"

View File

@ -129,7 +129,7 @@ test1136 test1137 test1138 test1139 test1140 test1141 test1142 test1143 \
test1144 test1145 test1146 test1147 test1148 test1149 test1150 test1151 \
test1152 test1153 test1154 test1155 test1156 test1157 test1158 test1159 \
\
test1160 test1161 test1162 test1163 test1164 \
test1160 test1161 test1162 test1163 test1164 test1168 \
test1170 test1171 test1172 \
\
test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 \
@ -176,7 +176,7 @@ test1525 test1526 test1527 test1528 test1529 test1530 test1531 test1532 \
test1533 test1534 test1535 test1536 test1537 test1538 \
test1540 test1541 \
test1550 test1551 test1552 test1553 test1554 test1555 test1556 test1557 \
test1558 test1560 test1561 test1562 \
test1558 test1559 test1560 test1561 test1562 \
\
test1590 test1591 test1592 \
\

78
curl/tests/data/test1168 Normal file
View File

@ -0,0 +1,78 @@
<testcase>
<info>
<keywords>
HTTP
HTTP GET
followlocation
</keywords>
</info>
# Server-side
<reply>
<data>
HTTP/1.1 301 This is a weirdo text message swsclose
Date: Thu, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Location: /data/11680002.txt
Connection: close
This server reply is for testing a simple Location: following
</data>
<data2>
HTTP/1.1 200 Followed here fine swsclose
Date: Thu, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Content-Length: 52
If this is received, the location following worked
</data2>
<datacheck>
HTTP/1.1 301 This is a weirdo text message swsclose
Date: Thu, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Location: /data/11680002.txt
Connection: close
HTTP/1.1 200 Followed here fine swsclose
Date: Thu, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Content-Length: 52
If this is received, the location following worked
</datacheck>
</reply>
# Client-side
<client>
<server>
http
</server>
<name>
HTTP redirect with credentials using # in user and password
</name>
<command>
http://%HOSTIP:%HTTPPORT/want/1168 -L -u "catmai#d:#DZaRJYrixKE*gFY"
</command>
</client>
# Verify data after the test has been "shot"
<verify>
<strip>
^User-Agent:.*
</strip>
<protocol>
GET /want/1168 HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Authorization: Basic Y2F0bWFpI2Q6I0RaYVJKWXJpeEtFKmdGWQ==
Accept: */*
GET /data/11680002.txt HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Authorization: Basic Y2F0bWFpI2Q6I0RaYVJKWXJpeEtFKmdGWQ==
Accept: */*
</protocol>
</verify>
</testcase>

View File

@ -74,6 +74,7 @@ int main(int argc, char *argv[])
curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
/* Here is a list of options the curl code used that cannot get generated

View File

@ -90,6 +90,7 @@ int main(int argc, char *argv[])
curl_easy_setopt(hnd, CURLOPT_HTTP09_ALLOWED, 1L);
curl_easy_setopt(hnd, CURLOPT_COOKIE, "chocolate=chip");
curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
curl_easy_setopt(hnd, CURLOPT_PROTOCOLS, (long)CURLPROTO_FILE |
(long)CURLPROTO_FTP |

View File

@ -81,6 +81,7 @@ int main(int argc, char *argv[])
curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
curl_easy_setopt(hnd, CURLOPT_HTTP09_ALLOWED, 1L);
curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
/* Here is a list of options the curl code used that cannot get generated

View File

@ -76,6 +76,7 @@ int main(int argc, char *argv[])
curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
curl_easy_setopt(hnd, CURLOPT_HTTP09_ALLOWED, 1L);
curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
/* Here is a list of options the curl code used that cannot get generated

View File

@ -147,6 +147,7 @@ int main(int argc, char *argv[])
curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
curl_easy_setopt(hnd, CURLOPT_HTTP09_ALLOWED, 1L);
curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
/* Here is a list of options the curl code used that cannot get generated

View File

@ -89,6 +89,7 @@ int main(int argc, char *argv[])
curl_easy_setopt(hnd, CURLOPT_POSTQUOTE, slist2);
curl_easy_setopt(hnd, CURLOPT_PREQUOTE, slist3);
curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
/* Here is a list of options the curl code used that cannot get generated

View File

@ -80,6 +80,7 @@ int main(int argc, char *argv[])
curl_easy_setopt(hnd, CURLOPT_URL, "smtp://%HOSTIP:%SMTPPORT/1406");
curl_easy_setopt(hnd, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
curl_easy_setopt(hnd, CURLOPT_MAIL_FROM, "sender@example.com");
curl_easy_setopt(hnd, CURLOPT_MAIL_RCPT, slist1);

View File

@ -62,6 +62,7 @@ int main(int argc, char *argv[])
curl_easy_setopt(hnd, CURLOPT_DIRLISTONLY, 1L);
curl_easy_setopt(hnd, CURLOPT_USERPWD, "user:secret");
curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
/* Here is a list of options the curl code used that cannot get generated

View File

@ -68,6 +68,7 @@ int main(int argc, char *argv[])
curl_easy_setopt(hnd, CURLOPT_USERPWD, "user:secret");
curl_easy_setopt(hnd, CURLOPT_HTTP09_ALLOWED, 1L);
curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
/* Here is a list of options the curl code used that cannot get generated

44
curl/tests/data/test1559 Normal file
View File

@ -0,0 +1,44 @@
<testcase>
<info>
<keywords>
CURLOPT_URL
</keywords>
</info>
<reply>
</reply>
<client>
<server>
none
</server>
# require HTTP so that CURLOPT_POSTFIELDS works as assumed
<features>
http
</features>
<tool>
lib1559
</tool>
<name>
Set excessive URL lengths
</name>
</client>
#
# Verify that the test runs to completion without crashing
<verify>
<errorcode>
0
</errorcode>
<stdout>
CURLOPT_URL 10000000 bytes URL == 43
CURLOPT_POSTFIELDS 10000000 bytes data == 0
CURLUPART_URL 10000000 bytes URL == 3
CURLUPART_SCHEME 10000000 bytes scheme == 3
CURLUPART_USER 10000000 bytes user == 3
</stdout>
</verify>
</testcase>

View File

@ -31,8 +31,7 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect \
lib1534 lib1535 lib1536 lib1537 lib1538 \
lib1540 lib1541 \
lib1550 lib1551 lib1552 lib1553 lib1554 lib1555 lib1556 lib1557 \
lib1558 \
lib1560 \
lib1558 lib1559 lib1560 \
lib1591 lib1592 \
lib1900 lib1905 \
lib2033
@ -529,6 +528,9 @@ lib1557_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1557
lib1558_SOURCES = lib1558.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1558_LDADD = $(TESTUTIL_LIBS)
lib1559_SOURCES = lib1559.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1559_LDADD = $(TESTUTIL_LIBS)
lib1560_SOURCES = lib1560.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1560_LDADD = $(TESTUTIL_LIBS)

View File

@ -0,0 +1,78 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.haxx.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
***************************************************************************/
#include "test.h"
#include "testutil.h"
#include "warnless.h"
#include "memdebug.h"
#define EXCESSIVE 10*1000*1000
int test(char *URL)
{
CURLcode res = 0;
CURL *curl = NULL;
char *longurl = malloc(EXCESSIVE);
CURLU *u;
(void)URL;
memset(longurl, 'a', EXCESSIVE);
longurl[EXCESSIVE-1] = 0;
global_init(CURL_GLOBAL_ALL);
easy_init(curl);
res = curl_easy_setopt(curl, CURLOPT_URL, longurl);
printf("CURLOPT_URL %d bytes URL == %d\n",
EXCESSIVE, (int)res);
res = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, longurl);
printf("CURLOPT_POSTFIELDS %d bytes data == %d\n",
EXCESSIVE, (int)res);
u = curl_url();
if(u) {
CURLUcode uc = curl_url_set(u, CURLUPART_URL, longurl, 0);
printf("CURLUPART_URL %d bytes URL == %d\n",
EXCESSIVE, (int)uc);
uc = curl_url_set(u, CURLUPART_SCHEME, longurl, CURLU_NON_SUPPORT_SCHEME);
printf("CURLUPART_SCHEME %d bytes scheme == %d\n",
EXCESSIVE, (int)uc);
uc = curl_url_set(u, CURLUPART_USER, longurl, 0);
printf("CURLUPART_USER %d bytes user == %d\n",
EXCESSIVE, (int)uc);
curl_url_cleanup(u);
}
free(longurl);
curl_easy_cleanup(curl);
curl_global_cleanup();
return 0;
test_cleanup:
curl_easy_cleanup(curl);
curl_global_cleanup();
return res; /* return the final return code */
}