diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 754275b78c..c4e26849aa 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -292,6 +292,7 @@ LIB_CFILES = \ transfer.c \ uint-bset.c \ uint-hash.c \ + uint-hashset.c \ uint-spbset.c \ uint-table.c \ url.c \ @@ -425,6 +426,7 @@ LIB_HFILES = \ transfer.h \ uint-bset.h \ uint-hash.h \ + uint-hashset.h \ uint-spbset.h \ uint-table.h \ url.h \ diff --git a/lib/cf-haproxy.c b/lib/cf-haproxy.c index 16ee25066c..e3286107a3 100644 --- a/lib/cf-haproxy.c +++ b/lib/cf-haproxy.c @@ -81,8 +81,8 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter *cf, if(result) return result; - if(data->set.str[STRING_HAPROXY_CLIENT_IP]) { - client_source_ip = data->set.str[STRING_HAPROXY_CLIENT_IP]; + client_source_ip = CURL_EASY_STR(data, STRING_HAPROXY_CLIENT_IP); + if(client_source_ip) { client_dest_ip = client_source_ip; is_ipv6 = !Curl_is_ipv4addr(client_source_ip); } diff --git a/lib/cf-socket.c b/lib/cf-socket.c index c72c30f7b7..77d850b299 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -656,9 +656,9 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, "random" */ /* how many port numbers to try to bind to, increasing one at a time */ int portnum = data->set.localportrange; - const char *dev = data->set.str[STRING_DEVICE]; - const char *iface_input = data->set.str[STRING_INTERFACE]; - const char *host_input = data->set.str[STRING_BINDHOST]; + const char *dev = CURL_EASY_STR(data, STRING_DEVICE); + const char *iface_input = CURL_EASY_STR(data, STRING_INTERFACE); + const char *host_input = CURL_EASY_STR(data, STRING_BINDHOST); const char *iface = iface_input ? iface_input : dev; const char *host = host_input ? host_input : dev; int sockerr; diff --git a/lib/cookie.c b/lib/cookie.c index c1a28bf8b1..51ce3a9c8b 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -1666,13 +1666,13 @@ void Curl_flush_cookies(struct Curl_easy *data, bool cleanup) might be cookie files that were not loaded so saving the file is the wrong thing. */ if(data->cookies) { - if(data->set.str[STRING_COOKIEJAR] && data->cookies->running) { + const char *cookiejar = CURL_EASY_STR(data, STRING_COOKIEJAR); + if(cookiejar && data->cookies->running) { /* if we have a destination file for all the cookies to get dumped to */ - CURLcode result = cookie_output(data, data->cookies, - data->set.str[STRING_COOKIEJAR]); + CURLcode result = cookie_output(data, data->cookies, cookiejar); if(result) infof(data, "WARNING: failed to save cookies in %s: %s", - data->set.str[STRING_COOKIEJAR], curl_easy_strerror(result)); + cookiejar, curl_easy_strerror(result)); } if(cleanup && (!data->share || (data->cookies != data->share->cookies))) { diff --git a/lib/easy.c b/lib/easy.c index 86c672d567..117af41f08 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -890,7 +890,6 @@ CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...) static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src) { CURLcode result = CURLE_OK; - enum dupstring i; enum dupblob j; /* Copy src->set into dst->set first, then deal with the strings @@ -899,17 +898,17 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src) #if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API) dst->set.mimepostp = NULL; #endif + dst->set.str_copypostfields = NULL; + + Curl_u8_strset_init(&dst->set.strings); /* clear all dest string and blob pointers first, in case we error out mid-function */ - memset(dst->set.str, 0, STRING_LAST * sizeof(char *)); memset(dst->set.blobs, 0, BLOB_LAST * sizeof(struct curl_blob *)); /* duplicate all strings */ - for(i = (enum dupstring)0; i < STRING_LASTZEROTERMINATED; i++) { - result = Curl_setstropt(&dst->set.str[i], src->set.str[i]); - if(result) - return result; - } + result = Curl_u8_strset_copy(&dst->set.strings, &src->set.strings); + if(result) + return result; /* duplicate all blobs */ for(j = (enum dupblob)0; j < BLOB_LAST; j++) { @@ -919,18 +918,18 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src) } /* duplicate memory areas pointed to */ - i = STRING_COPYPOSTFIELDS; - if(src->set.str[i]) { + if(src->set.str_copypostfields) { if(src->set.postfieldsize == -1) - dst->set.str[i] = curlx_strdup(src->set.str[i]); + dst->set.str_copypostfields = curlx_strdup(src->set.str_copypostfields); else /* postfieldsize is curl_off_t, curlx_memdup() takes a size_t ... */ - dst->set.str[i] = curlx_memdup(src->set.str[i], - curlx_sotouz(src->set.postfieldsize)); - if(!dst->set.str[i]) + dst->set.str_copypostfields = + curlx_memdup(src->set.str_copypostfields, + curlx_sotouz(src->set.postfieldsize)); + if(!dst->set.str_copypostfields) return CURLE_OUT_OF_MEMORY; /* point to the new copy */ - dst->set.postfields = dst->set.str[i]; + dst->set.postfields = dst->set.str_copypostfields; } #if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API) @@ -974,6 +973,7 @@ CURL *curl_easy_duphandle(CURL *curl) if(CURL_EAPI_ENTER(&guard, curl, easy_duphandle, NULL)) { struct Curl_easy *data = curl; + const char *str; outcurl = curlx_calloc(1, sizeof(struct Curl_easy)); if(!outcurl) @@ -1047,8 +1047,9 @@ CURL *curl_easy_duphandle(CURL *curl) /* Reinitialize an SSL engine for the new handle * note: the engine name has already been copied by dupset */ - if(outcurl->set.str[STRING_SSL_ENGINE]) { - if(Curl_ssl_set_engine(outcurl, outcurl->set.str[STRING_SSL_ENGINE])) + str = CURL_EASY_STR(outcurl, STRING_SSL_ENGINE); + if(str) { + if(Curl_ssl_set_engine(outcurl, str)) goto fail; } @@ -1057,8 +1058,9 @@ CURL *curl_easy_duphandle(CURL *curl) outcurl->asi = Curl_altsvc_init(); if(!outcurl->asi) goto fail; - if(outcurl->set.str[STRING_ALTSVC]) - (void)Curl_altsvc_load(outcurl->asi, outcurl->set.str[STRING_ALTSVC]); + str = CURL_EASY_STR(outcurl, STRING_ALTSVC); + if(str) + (void)Curl_altsvc_load(outcurl->asi, str); } #endif #ifndef CURL_DISABLE_HSTS @@ -1066,9 +1068,9 @@ CURL *curl_easy_duphandle(CURL *curl) outcurl->hsts = Curl_hsts_init(); if(!outcurl->hsts) goto fail; - if(outcurl->set.str[STRING_HSTS]) - (void)Curl_hsts_loadfile(outcurl, - outcurl->hsts, outcurl->set.str[STRING_HSTS]); + str = CURL_EASY_STR(outcurl, STRING_HSTS); + if(str) + (void)Curl_hsts_loadfile(outcurl, outcurl->hsts, str); (void)Curl_hsts_loadcb(outcurl, outcurl->hsts); /* Copy entries learned at runtime. (E.g. Strict-Transport-Security diff --git a/lib/ftp.c b/lib/ftp.c index 3a4859d188..5a880de78d 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -1333,7 +1333,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, curl_socklen_t sslen; char hbuf[NI_MAXHOST]; const char *host = NULL; - const char *string_ftpport = data->set.str[STRING_FTPPORT]; + const char *string_ftpport = CURL_EASY_STR(data, STRING_FTPPORT); struct Curl_dns_entry *dns_entry = NULL; const struct Curl_addrinfo *res = NULL; const struct Curl_addrinfo *ai = NULL; @@ -1477,8 +1477,8 @@ static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data, to prepare the server for the upcoming PASV */ if(!ftpc->file) result = Curl_pp_sendf(data, &ftpc->pp, "PRET %s", - data->set.str[STRING_CUSTOMREQUEST] ? - data->set.str[STRING_CUSTOMREQUEST] : + CURL_EASY_STR(data, STRING_CUSTOMREQUEST) ? + CURL_EASY_STR(data, STRING_CUSTOMREQUEST) : (data->state.list_only ? "NLST" : "LIST")); else if(data->state.upload) result = Curl_pp_sendf(data, &ftpc->pp, "PRET STOR %s", ftpc->file); @@ -1572,8 +1572,8 @@ static CURLcode ftp_state_list(struct Curl_easy *data, } cmd = curl_maprintf("%s%s%.*s", - data->set.str[STRING_CUSTOMREQUEST] ? - data->set.str[STRING_CUSTOMREQUEST] : + CURL_EASY_STR(data, STRING_CUSTOMREQUEST) ? + CURL_EASY_STR(data, STRING_CUSTOMREQUEST) : (data->state.list_only ? "NLST" : "LIST"), lstArg ? " " : "", lstArglen, lstArg ? lstArg : ""); @@ -2956,7 +2956,7 @@ static CURLcode ftp_state_user_resp(struct Curl_easy *data, result = ftp_state_loggedin(data, ftpc); } else if(ftpcode == 332) { - const char *account = data->set.str[STRING_FTP_ACCOUNT]; + const char *account = CURL_EASY_STR(data, STRING_FTP_ACCOUNT); if(!account) { failf(data, "ACCT requested but none available"); result = CURLE_LOGIN_DENIED; @@ -2977,7 +2977,7 @@ static CURLcode ftp_state_user_resp(struct Curl_easy *data, 530 User ... access denied (the server denies to log the specified user) */ - const char *alt = data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]; + const char *alt = CURL_EASY_STR(data, STRING_FTP_ALTERNATIVE_TO_USER); if(alt && !ftpc->ftp_trying_alternative) { /* Ok, USER failed. Let's try the supplied command. */ if(ftp_has_ctrl(alt)) { @@ -4436,16 +4436,16 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; /* clone connection related data that is FTP specific */ - if(data->set.str[STRING_FTP_ACCOUNT]) { - ftpc->account = curlx_strdup(data->set.str[STRING_FTP_ACCOUNT]); + if(CURL_EASY_STR(data, STRING_FTP_ACCOUNT)) { + ftpc->account = curlx_strdup(CURL_EASY_STR(data, STRING_FTP_ACCOUNT)); if(!ftpc->account) { Curl_conn_meta_remove(conn, CURL_META_FTP_CONN); return CURLE_OUT_OF_MEMORY; } } - if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]) { + if(CURL_EASY_STR(data, STRING_FTP_ALTERNATIVE_TO_USER)) { ftpc->alternative_to_user = - curlx_strdup(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]); + curlx_strdup(CURL_EASY_STR(data, STRING_FTP_ALTERNATIVE_TO_USER)); if(!ftpc->alternative_to_user) { curlx_safefree(ftpc->account); Curl_conn_meta_remove(conn, CURL_META_FTP_CONN); diff --git a/lib/getinfo.c b/lib/getinfo.c index 30ee405e99..23f1de270c 100644 --- a/lib/getinfo.c +++ b/lib/getinfo.c @@ -86,7 +86,7 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info, } break; case CURLINFO_EFFECTIVE_METHOD: { - const char *m = data->set.str[STRING_CUSTOMREQUEST]; + const char *m = CURL_EASY_STR(data, STRING_CUSTOMREQUEST); if(!m) { if(data->set.opt_no_body) m = "HEAD"; @@ -149,7 +149,7 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info, break; case CURLINFO_RTSP_SESSION_ID: #ifndef CURL_DISABLE_RTSP - *param_charp = data->set.str[STRING_RTSP_SESSION_ID]; + *param_charp = CURL_EASY_STR(data, STRING_RTSP_SESSION_ID); #else *param_charp = NULL; #endif diff --git a/lib/http.c b/lib/http.c index 5701bdc09b..98608793c7 100644 --- a/lib/http.c +++ b/lib/http.c @@ -1153,7 +1153,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy, static void http_switch_to_get(struct Curl_easy *data, int code) { - const char *req = data->set.str[STRING_CUSTOMREQUEST]; + const char *req = CURL_EASY_STR(data, STRING_CUSTOMREQUEST); if((req || data->state.httpreq != HTTPREQ_GET) && (data->set.http_follow_mode == CURLFOLLOW_OBEYCODE)) { @@ -1306,8 +1306,8 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl, rewind_result = Curl_req_soft_reset(&data->req, data); infof(data, "Issue another request to this URL: '%s'", follow_url); if((data->set.http_follow_mode == CURLFOLLOW_FIRSTONLY) && - data->set.str[STRING_CUSTOMREQUEST] && - !data->state.http_ignorecustom) { + !data->state.http_ignorecustom && + CURL_EASY_STR(data, STRING_CUSTOMREQUEST)) { data->state.http_ignorecustom = TRUE; infof(data, "Drop custom request method for next request"); } @@ -1991,9 +1991,9 @@ void Curl_http_method(struct Curl_easy *data, httpreq = HTTPREQ_PUT; /* Now set the 'request' pointer to the proper request string */ - if(data->set.str[STRING_CUSTOMREQUEST] && - !data->state.http_ignorecustom) { - request = data->set.str[STRING_CUSTOMREQUEST]; + if(!data->state.http_ignorecustom && + CURL_EASY_STR(data, STRING_CUSTOMREQUEST)) { + request = CURL_EASY_STR(data, STRING_CUSTOMREQUEST); } else { if(data->req.no_body) @@ -2124,8 +2124,8 @@ static CURLcode http_target(struct Curl_easy *data, struct connectdata *conn = data->conn; #endif - if(data->set.str[STRING_TARGET]) { - path = data->set.str[STRING_TARGET]; + if(CURL_EASY_STR(data, STRING_TARGET)) { + path = CURL_EASY_STR(data, STRING_TARGET); query = NULL; } @@ -2194,8 +2194,8 @@ static CURLcode http_target(struct Curl_easy *data, curl_url_cleanup(h); /* target or URL */ - result = curlx_dyn_add(r, data->set.str[STRING_TARGET] ? - data->set.str[STRING_TARGET] : url); + result = curlx_dyn_add(r, CURL_EASY_STR(data, STRING_TARGET) ? + CURL_EASY_STR(data, STRING_TARGET) : url); curlx_free(url); if(result) return result; @@ -2576,12 +2576,12 @@ static CURLcode http_cookies(struct Curl_easy *data, struct dynbuf *r) { CURLcode result = CURLE_OK; - char *addcookies = NULL; + const char *addcookies = NULL; bool linecap = FALSE; - if(data->set.str[STRING_COOKIE] && + if(CURL_EASY_STR(data, STRING_COOKIE) && !Curl_checkheaders(data, STRCONST("Cookie")) && Curl_auth_allowed_to_host(data)) - addcookies = data->set.str[STRING_COOKIE]; + addcookies = CURL_EASY_STR(data, STRING_COOKIE); if(data->cookies || addcookies) { struct Curl_llist list; @@ -2957,14 +2957,12 @@ static CURLcode http_add_hd(struct Curl_easy *data, result = curlx_dyn_add(req, data->state.rangeline); break; - case H1_HD_USER_AGENT: - if(!Curl_checkheaders(data, STRCONST("User-Agent"))) { - if(data->set.str[STRING_USERAGENT] && - *data->set.str[STRING_USERAGENT]) - result = curlx_dyn_addf(req, "User-Agent: %s\r\n", - data->set.str[STRING_USERAGENT]); - } + case H1_HD_USER_AGENT: { + const char *ua = CURL_EASY_STR(data, STRING_USERAGENT); + if(ua && *ua && !Curl_checkheaders(data, STRCONST("User-Agent"))) + result = curlx_dyn_addf(req, "User-Agent: %s\r\n", ua); break; + } case H1_HD_ACCEPT: if(!Curl_checkheaders(data, STRCONST("Accept"))) @@ -2981,12 +2979,12 @@ static CURLcode http_add_hd(struct Curl_easy *data, #endif break; - case H1_HD_ACCEPT_ENCODING: - if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) && - data->set.str[STRING_ENCODING]) - result = curlx_dyn_addf(req, "Accept-Encoding: %s\r\n", - data->set.str[STRING_ENCODING]); + case H1_HD_ACCEPT_ENCODING: { + const char *enc = CURL_EASY_STR(data, STRING_ENCODING); + if(enc && !Curl_checkheaders(data, STRCONST("Accept-Encoding"))) + result = curlx_dyn_addf(req, "Accept-Encoding: %s\r\n", enc); break; + } case H1_HD_REFERER: if(Curl_bufref_ptr(&data->state.referer) && @@ -3317,7 +3315,7 @@ static CURLcode http_header_c(struct Curl_easy *data, } } while(1); } - v = (!k->http_bodyless && data->set.str[STRING_ENCODING]) ? + v = (!k->http_bodyless && CURL_EASY_STR(data, STRING_ENCODING)) ? HD_VAL(hd, hdlen, "Content-Encoding:") : NULL; if(v) { /* diff --git a/lib/http2.c b/lib/http2.c index 47e3e075bc..9ac0d20fb3 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -2088,10 +2088,11 @@ static CURLcode h2_submit(struct h2_stream_ctx **pstream, if(result) goto out; - result = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, - !data->state.http_ignorecustom ? - data->set.str[STRING_CUSTOMREQUEST] : NULL, - 0, &nwritten); + result = Curl_h1_req_parse_read( + &stream->h1, buf, len, NULL, + !data->state.http_ignorecustom ? + CURL_EASY_STR(data, STRING_CUSTOMREQUEST) : NULL, + 0, &nwritten); if(result) goto out; *pnwritten = nwritten; diff --git a/lib/http_aws_sigv4.c b/lib/http_aws_sigv4.c index b142749f88..b16c2cd2aa 100644 --- a/lib/http_aws_sigv4.c +++ b/lib/http_aws_sigv4.c @@ -816,7 +816,7 @@ static CURLcode parse_sigv4_params(struct Curl_easy *data, struct Curl_str *region, struct Curl_str *service) { - const char *line = data->set.str[STRING_AWS_SIGV4]; + const char *line = CURL_EASY_STR(data, STRING_AWS_SIGV4); if(!line || !*line) line = "aws:amz"; diff --git a/lib/http_httpsig.c b/lib/http_httpsig.c index c0329261dc..37f23a09cb 100644 --- a/lib/http_httpsig.c +++ b/lib/http_httpsig.c @@ -376,7 +376,7 @@ static CURLcode parse_components(struct Curl_easy *data, size_t *ncomp_out, char **hdrs_copy_out) { - const char *hdrs = data->set.str[STRING_HTTPSIG_HEADERS]; + const char *hdrs = CURL_EASY_STR(data, STRING_HTTPSIG_HEADERS); size_t ncomp = 0; *hdrs_copy_out = NULL; @@ -534,8 +534,8 @@ CURLcode Curl_output_httpsig(struct Curl_easy *data) const char *query; Curl_HttpReq httpreq; const char *method = NULL; - const char *hexkey; - const char *keyid; + const char *hexkey = CURL_EASY_STR(data, STRING_HTTPSIG_KEY); + const char *keyid = CURL_EASY_STR(data, STRING_HTTPSIG_KEYID); enum httpsig_alg alg; time_t created; struct dynbuf sig_params; @@ -560,9 +560,6 @@ CURLcode Curl_output_httpsig(struct Curl_easy *data) return CURLE_BAD_FUNCTION_ARGUMENT; } - hexkey = data->set.str[STRING_HTTPSIG_KEY]; - keyid = data->set.str[STRING_HTTPSIG_KEYID]; - if(!hexkey || !*hexkey) { failf(data, "httpsig: CURLOPT_HTTPSIG_KEY is required"); return CURLE_BAD_FUNCTION_ARGUMENT; diff --git a/lib/http_proxy.c b/lib/http_proxy.c index 96cd101ca7..7774589ecd 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -201,6 +201,7 @@ static CURLcode http_proxy_create_CONNECT(struct httpreq **preq, proxy_http_ver ver) { char *authority = NULL; + const char *ua; int httpversion = proxy_http_ver_major(ver); CURLcode result; struct httpreq *req = NULL; @@ -242,10 +243,10 @@ static CURLcode http_proxy_create_CONNECT(struct httpreq **preq, goto out; } + ua = CURL_EASY_STR(data, STRING_USERAGENT); if(!Curl_checkProxyheaders(data, cf->conn, STRCONST("User-Agent")) && - data->set.str[STRING_USERAGENT] && *data->set.str[STRING_USERAGENT]) { - result = Curl_dynhds_cadd(&req->headers, "User-Agent", - data->set.str[STRING_USERAGENT]); + ua && *ua) { + result = Curl_dynhds_cadd(&req->headers, "User-Agent", ua); if(result) goto out; } @@ -276,7 +277,7 @@ static CURLcode http_proxy_create_CONNECTUDP(struct httpreq **preq, struct Curl_peer *dest, proxy_http_ver ver) { - const char *proxy_scheme = "http"; + const char *proxy_scheme = "http", *ua; const char *proxy_host = cf->conn->http_proxy.peer->hostname; int httpversion = proxy_http_ver_major(ver); char *authority = NULL; @@ -381,11 +382,11 @@ static CURLcode http_proxy_create_CONNECTUDP(struct httpreq **preq, goto out; } + ua = CURL_EASY_STR(data, STRING_USERAGENT); if(ver == PROXY_HTTP_V1 && !Curl_checkProxyheaders(data, cf->conn, STRCONST("User-Agent")) && - data->set.str[STRING_USERAGENT] && *data->set.str[STRING_USERAGENT]) { - result = Curl_dynhds_cadd(&req->headers, "User-Agent", - data->set.str[STRING_USERAGENT]); + ua && *ua) { + result = Curl_dynhds_cadd(&req->headers, "User-Agent", ua); if(result) goto out; } diff --git a/lib/imap.c b/lib/imap.c index a1a4ac4363..d854a2e8ea 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -1923,7 +1923,7 @@ static CURLcode imap_parse_custom_request(struct Curl_easy *data, struct IMAP *imap) { CURLcode result = CURLE_OK; - const char *custom = data->set.str[STRING_CUSTOMREQUEST]; + const char *custom = CURL_EASY_STR(data, STRING_CUSTOMREQUEST); if(custom) { /* URL decode the custom request */ diff --git a/lib/pop3.c b/lib/pop3.c index 7634dfb629..b32663ce14 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -250,7 +250,7 @@ static CURLcode pop3_parse_custom_request(struct Curl_easy *data) { CURLcode result = CURLE_OK; struct POP3 *pop3 = Curl_meta_get(data, CURL_META_POP3_EASY); - const char *custom = data->set.str[STRING_CUSTOMREQUEST]; + const char *custom = CURL_EASY_STR(data, STRING_CUSTOMREQUEST); if(!pop3) return CURLE_FAILED_INIT; diff --git a/lib/proxy.c b/lib/proxy.c index b69d89a2ce..5d7c02579d 100644 --- a/lib/proxy.c +++ b/lib/proxy.c @@ -451,21 +451,21 @@ static CURLcode parse_proxy(struct Curl_easy *data, if(proxyuser || proxypasswd) { result = Curl_creds_create(proxyuser, proxypasswd, NULL, NULL, - data->set.str[STRING_PROXY_SERVICE_NAME], + CURL_EASY_STR(data, STRING_PROXY_SERVICE_NAME), CREDS_URL, &proxyinfo->creds); if(result) goto error; } else if(!for_pre_proxy && - (data->set.str[STRING_PROXYUSERNAME] || - data->set.str[STRING_PROXYPASSWORD] || - data->set.str[STRING_PROXY_SERVICE_NAME])) { + (CURL_EASY_STR(data, STRING_PROXYUSERNAME) || + CURL_EASY_STR(data, STRING_PROXYPASSWORD) || + CURL_EASY_STR(data, STRING_PROXY_SERVICE_NAME))) { /* No user/passwd in URL, if this is not a pre-proxy, the * CURLOPT_PROXY* settings apply. */ - result = Curl_creds_create(data->set.str[STRING_PROXYUSERNAME], - data->set.str[STRING_PROXYPASSWORD], + result = Curl_creds_create(CURL_EASY_STR(data, STRING_PROXYUSERNAME), + CURL_EASY_STR(data, STRING_PROXYPASSWORD), NULL, NULL, - data->set.str[STRING_PROXY_SERVICE_NAME], + CURL_EASY_STR(data, STRING_PROXY_SERVICE_NAME), CREDS_OPTION, &proxyinfo->creds); } else @@ -498,7 +498,7 @@ static bool proxy_do_not_proxy(struct Curl_easy *data) if(data->state.origin->scheme->flags & PROTOPT_NONETWORK) return TRUE; - no_proxy = data->set.str[STRING_NOPROXY]; + no_proxy = CURL_EASY_STR(data, STRING_NOPROXY); if(!no_proxy) { const char *p = "no_proxy"; env_no_proxy = curl_getenv(p); @@ -521,6 +521,7 @@ CURLcode Curl_proxy_init_conn(struct Curl_easy *data, { char *proxy = NULL; char *pre_proxy = NULL; + const char *str = NULL; bool do_env_detect = TRUE; CURLcode result = CURLE_OK; @@ -536,9 +537,10 @@ CURLcode Curl_proxy_init_conn(struct Curl_easy *data, * Detect what (if any) proxy to use *************************************************************/ /* the empty config strings disable proxy use and env detects */ - if(data->set.str[STRING_PROXY]) { - if(*data->set.str[STRING_PROXY]) { - proxy = curlx_strdup(data->set.str[STRING_PROXY]); + str = CURL_EASY_STR(data, STRING_PROXY); + if(str) { + if(*str) { + proxy = curlx_strdup(str); /* if global proxy is set, this is it */ if(!proxy) { failf(data, "memory shortage"); @@ -550,9 +552,10 @@ CURLcode Curl_proxy_init_conn(struct Curl_easy *data, do_env_detect = FALSE; } - if(data->set.str[STRING_PRE_PROXY]) { - if(*data->set.str[STRING_PRE_PROXY]) { - pre_proxy = curlx_strdup(data->set.str[STRING_PRE_PROXY]); + str = CURL_EASY_STR(data, STRING_PRE_PROXY); + if(str) { + if(*str) { + pre_proxy = curlx_strdup(str); /* if global socks proxy is set, this is it */ if(!pre_proxy) { failf(data, "memory shortage"); diff --git a/lib/rtsp.c b/lib/rtsp.c index c31263a8c8..fabdda3d3e 100644 --- a/lib/rtsp.c +++ b/lib/rtsp.c @@ -336,11 +336,11 @@ static CURLcode rtsp_setup_request(struct Curl_easy *data, CURLcode result = CURLE_OK; struct connectdata *conn = data->conn; - b->session_id = data->set.str[STRING_RTSP_SESSION_ID]; + b->session_id = CURL_EASY_STR(data, STRING_RTSP_SESSION_ID); /* Stream URI. Default to server '*' if not specified */ - if(data->set.str[STRING_RTSP_STREAM_URI]) - b->stream_uri = data->set.str[STRING_RTSP_STREAM_URI]; + if(CURL_EASY_STR(data, STRING_RTSP_STREAM_URI)) + b->stream_uri = CURL_EASY_STR(data, STRING_RTSP_STREAM_URI); else b->stream_uri = "*"; @@ -348,10 +348,10 @@ static CURLcode rtsp_setup_request(struct Curl_easy *data, b->transport = Curl_checkheaders(data, STRCONST("Transport")); if(rtspreq == RTSPREQ_SETUP && !b->transport) { /* New Transport: setting? */ - if(data->set.str[STRING_RTSP_TRANSPORT]) { - result = rtsp_header_alloc("Transport", - data->set.str[STRING_RTSP_TRANSPORT], - &b->transport); + if(CURL_EASY_STR(data, STRING_RTSP_TRANSPORT)) { + result = rtsp_header_alloc( + "Transport", CURL_EASY_STR(data, STRING_RTSP_TRANSPORT), + &b->transport); if(result) return result; b->transport_alloc = TRUE; @@ -371,9 +371,9 @@ static CURLcode rtsp_setup_request(struct Curl_easy *data, /* Accept-Encoding header */ if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) && - data->set.str[STRING_ENCODING]) { + CURL_EASY_STR(data, STRING_ENCODING)) { result = rtsp_header_alloc("Accept-Encoding", - data->set.str[STRING_ENCODING], + CURL_EASY_STR(data, STRING_ENCODING), &b->accept_encoding); if(result) return result; @@ -430,6 +430,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) { CURLcode result = CURLE_OK; const unsigned char rtspreq = data->set.rtspreq; + const char *str; struct RTSP *rtsp = Curl_meta_get(data, CURL_META_RTSP_EASY); struct dynbuf req_buffer; struct rtsp_blocks block; @@ -506,12 +507,11 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) block.range ? block.range : "", block.referrer ? block.referrer : ""); - if(!result && - !Curl_checkheaders(data, STRCONST("User-Agent")) && - data->set.str[STRING_USERAGENT] && *data->set.str[STRING_USERAGENT]) + str = CURL_EASY_STR(data, STRING_USERAGENT); + if(!result && str && *str && + !Curl_checkheaders(data, STRCONST("User-Agent"))) result = curlx_dyn_addf(&req_buffer, - "User-Agent: %s\r\n", - data->set.str[STRING_USERAGENT]); + "User-Agent: %s\r\n", str); if(!result) result = curlx_dyn_addf(&req_buffer, @@ -976,7 +976,7 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header) data->state.rtsp_CSeq_recv = rtsp->CSeq_recv = (uint32_t)CSeq; } else if(checkprefix("Session:", header)) { - const char *start, *end; + const char *start, *end, *str; size_t idlen; /* Find the first non-space letter */ @@ -999,24 +999,24 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header) end++; idlen = end - start; - if(data->set.str[STRING_RTSP_SESSION_ID]) { + str = CURL_EASY_STR(data, STRING_RTSP_SESSION_ID); + if(str) { /* If the Session ID is set, then compare */ - if(strlen(data->set.str[STRING_RTSP_SESSION_ID]) != idlen || - strncmp(start, data->set.str[STRING_RTSP_SESSION_ID], idlen)) { + if(strlen(str) != idlen || + strncmp(start, str, idlen)) { failf(data, "Got RTSP Session ID Line [%s], but wanted ID [%s]", - start, data->set.str[STRING_RTSP_SESSION_ID]); + start, str); return CURLE_RTSP_SESSION_ERROR; } } else { /* If the Session ID is not set, and we find it in a response, then set * it. - */ - - /* Copy the id substring into a new buffer */ - data->set.str[STRING_RTSP_SESSION_ID] = curlx_memdup0(start, idlen); - if(!data->set.str[STRING_RTSP_SESSION_ID]) + * Copy the id substring into a new buffer */ + void *mem = curlx_memdup0(start, idlen); + if(!mem || + CURL_EASY_STR_SETN(data, STRING_RTSP_SESSION_ID, mem)) return CURLE_OUT_OF_MEMORY; } } diff --git a/lib/setopt.c b/lib/setopt.c index d6c641f780..fe991a145f 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -78,23 +78,14 @@ static CURLcode setopt_set_timeout_ms(timediff_t *ptimeout_ms, long ms) return CURLE_OK; } -CURLcode Curl_setstropt(char **charp, const char *s) +CURLcode Curl_setstropt(struct Curl_easy *data, + enum dupstring id, const char *s) { - /* Release the previous storage at `charp' and replace by a dynamic storage - copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */ + DEBUGASSERT((unsigned)id <= UINT8_MAX); + if(s && (strlen(s) > CURL_MAX_INPUT_LENGTH)) + return CURLE_BAD_FUNCTION_ARGUMENT; - curlx_safefree(*charp); - - if(s) { - if(strlen(s) > CURL_MAX_INPUT_LENGTH) - return CURLE_BAD_FUNCTION_ARGUMENT; - - *charp = curlx_strdup(s); - if(!*charp) - return CURLE_OUT_OF_MEMORY; - } - - return CURLE_OK; + return CURL_EASY_STR_SET(data, (uint8_t)id, s); } CURLcode Curl_setblobopt(struct curl_blob **blobp, @@ -160,34 +151,34 @@ static CURLcode setstropt_userpwd(const char *option, char **userp, return CURLE_OK; } -static CURLcode setstropt_interface(char *option, char **devp, - char **ifacep, char **hostp) +static CURLcode setstropt_interface(struct Curl_easy *data, char *option) { char *dev = NULL; char *iface = NULL; char *host = NULL; CURLcode result; - DEBUGASSERT(devp); - DEBUGASSERT(ifacep); - DEBUGASSERT(hostp); - if(option) { /* Parse the interface details if set, otherwise clear them all */ result = Curl_parse_interface(option, &dev, &iface, &host); if(result) return result; } - curlx_free(*devp); - *devp = dev; - curlx_free(*ifacep); - *ifacep = iface; - - curlx_free(*hostp); - *hostp = host; - - return CURLE_OK; + result = CURL_EASY_STR_SETN(data, STRING_DEVICE, dev); + dev = NULL; + if(!result) { + result = CURL_EASY_STR_SETN(data, STRING_INTERFACE, iface); + iface = NULL; + } + if(!result) { + result = CURL_EASY_STR_SETN(data, STRING_BINDHOST, host); + host = NULL; + } + curlx_free(dev); + curlx_free(iface); + curlx_free(host); + return result; } #ifdef USE_SSL @@ -952,7 +943,7 @@ static CURLcode setopt_long_ssl(struct Curl_easy *data, CURLoption option, case CURLOPT_SSL_ENABLE_NPN: break; case CURLOPT_SSLENGINE_DEFAULT: - curlx_safefree(s->str[STRING_SSL_ENGINE]); + CURL_EASY_STR_CLEAR(data, STRING_SSL_ENGINE); result = Curl_ssl_set_engine_default(data); break; default: @@ -1211,9 +1202,8 @@ static CURLcode setopt_long_misc(struct Curl_easy *data, CURLoption option, case CURLOPT_POSTFIELDSIZE: if(arg < -1) return CURLE_BAD_FUNCTION_ARGUMENT; - if(s->postfieldsize < arg && - s->postfields == s->str[STRING_COPYPOSTFIELDS]) { - curlx_safefree(s->str[STRING_COPYPOSTFIELDS]); + if(s->postfieldsize < arg && s->str_copypostfields) { + curlx_safefree(s->str_copypostfields); s->postfields = NULL; } s->postfieldsize = arg; @@ -1458,7 +1448,7 @@ static CURLcode setopt_pointers(struct Curl_easy *data, CURLoption option, * pass CURLU to set URL */ Curl_bufref_free(&data->state.url); - curlx_safefree(s->str[STRING_SET_URL]); + CURL_EASY_STR_CLEAR(data, STRING_SET_URL); s->uh = va_arg(param, CURLU *); break; #ifndef CURL_DISABLE_HTTP @@ -1604,13 +1594,14 @@ static CURLcode cookiefile(struct Curl_easy *data, const char *ptr) #ifndef CURL_DISABLE_PROXY static CURLcode setproxy(struct Curl_easy *data, const char *proxy) { - if((data->set.str[STRING_PROXY] && proxy) && + const char *str = CURL_EASY_STR(data, STRING_PROXY); + if(str && proxy && /* there was one set, is this a new one? */ - !strcmp(data->set.str[STRING_PROXY], proxy)) + !strcmp(str, proxy)) return CURLE_OK; /* same one as before */ changeproxy(data); - return Curl_setstropt(&data->set.str[STRING_PROXY], proxy); + return Curl_setstropt(data, STRING_PROXY, proxy); } static CURLcode setopt_cptr_proxy(struct Curl_easy *data, CURLoption option, @@ -1629,15 +1620,21 @@ static CURLcode setopt_cptr_proxy(struct Curl_easy *data, CURLoption option, /* URL decode the components */ if(!result) { - curlx_safefree(s->str[STRING_PROXYUSERNAME]); - curlx_safefree(s->str[STRING_PROXYPASSWORD]); - if(u) - result = Curl_urldecode(u, 0, &s->str[STRING_PROXYUSERNAME], NULL, - REJECT_ZERO); + char *str = NULL; + CURL_EASY_STR_CLEAR(data, STRING_PROXYUSERNAME); + CURL_EASY_STR_CLEAR(data, STRING_PROXYPASSWORD); + if(u) { + result = Curl_urldecode(u, 0, &str, NULL, REJECT_ZERO); + if(!result) + result = Curl_u8_strset_setn(&s->strings, STRING_PROXYUSERNAME, str); + } + if(!result && p) { + str = NULL; + result = Curl_urldecode(p, 0, &str, NULL, REJECT_ZERO); + if(!result) + result = Curl_u8_strset_setn(&s->strings, STRING_PROXYPASSWORD, str); + } } - if(!result && p) - result = Curl_urldecode(p, 0, &s->str[STRING_PROXYPASSWORD], NULL, - REJECT_ZERO); curlx_free(u); curlx_strzero(p); curlx_free(p); @@ -1647,55 +1644,55 @@ static CURLcode setopt_cptr_proxy(struct Curl_easy *data, CURLoption option, /* * authentication username to use in the operation */ - return Curl_setstropt(&s->str[STRING_PROXYUSERNAME], ptr); + return Curl_setstropt(data, STRING_PROXYUSERNAME, ptr); case CURLOPT_PROXYPASSWORD: /* * authentication password to use in the operation */ - return Curl_setstropt(&s->str[STRING_PROXYPASSWORD], ptr); + return Curl_setstropt(data, STRING_PROXYPASSWORD, ptr); case CURLOPT_NOPROXY: /* * proxy exception list */ - return Curl_setstropt(&s->str[STRING_NOPROXY], ptr); + return Curl_setstropt(data, STRING_NOPROXY, ptr); case CURLOPT_PROXY_SSLCERT: /* * String that holds filename of the SSL certificate to use for proxy */ - return Curl_setstropt(&s->str[STRING_CERT_PROXY], ptr); + return Curl_setstropt(data, STRING_CERT_PROXY, ptr); case CURLOPT_PROXY_SSLCERTTYPE: /* * String that holds file type of the SSL certificate to use for proxy */ - return Curl_setstropt(&s->str[STRING_CERT_TYPE_PROXY], ptr); + return Curl_setstropt(data, STRING_CERT_TYPE_PROXY, ptr); case CURLOPT_PROXY_SSLKEY: /* * String that holds filename of the SSL key to use for proxy */ - return Curl_setstropt(&s->str[STRING_KEY_PROXY], ptr); + return Curl_setstropt(data, STRING_KEY_PROXY, ptr); case CURLOPT_PROXY_KEYPASSWD: /* * String that holds the SSL private key password for proxy. */ - return Curl_setstropt(&s->str[STRING_KEY_PASSWD_PROXY], ptr); + return Curl_setstropt(data, STRING_KEY_PASSWD_PROXY, ptr); case CURLOPT_PROXY_SSLKEYTYPE: /* * String that holds file type of the SSL key to use for proxy */ - return Curl_setstropt(&s->str[STRING_KEY_TYPE_PROXY], ptr); + return Curl_setstropt(data, STRING_KEY_TYPE_PROXY, ptr); case CURLOPT_PROXY_SSL_CIPHER_LIST: if(Curl_ssl_supports(data, SSLSUPP_CIPHER_LIST)) { /* set a list of cipher we want to use in the SSL connection for proxy */ - return Curl_setstropt(&s->str[STRING_SSL_CIPHER_LIST_PROXY], ptr); + return Curl_setstropt(data, STRING_SSL_CIPHER_LIST_PROXY, ptr); } else return CURLE_NOT_BUILT_IN; case CURLOPT_PROXY_TLS13_CIPHERS: if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) /* set preferred list of TLS 1.3 cipher suites for proxy */ - return Curl_setstropt(&s->str[STRING_SSL_CIPHER13_LIST_PROXY], ptr); + return Curl_setstropt(data, STRING_SSL_CIPHER13_LIST_PROXY, ptr); else return CURLE_NOT_BUILT_IN; case CURLOPT_PROXY: @@ -1717,13 +1714,13 @@ static CURLcode setopt_cptr_proxy(struct Curl_easy *data, CURLoption option, * If the proxy is set to "" or NULL we explicitly say that we do not want * to use the socks proxy. */ - return Curl_setstropt(&s->str[STRING_PRE_PROXY], ptr); + return Curl_setstropt(data, STRING_PRE_PROXY, ptr); case CURLOPT_SOCKS5_GSSAPI_SERVICE: case CURLOPT_PROXY_SERVICE_NAME: /* * Set proxy authentication service name for Kerberos 5 and SPNEGO */ - return Curl_setstropt(&s->str[STRING_PROXY_SERVICE_NAME], ptr); + return Curl_setstropt(data, STRING_PROXY_SERVICE_NAME, ptr); case CURLOPT_PROXY_PINNEDPUBLICKEY: /* * Set pinned public key for SSL connection. @@ -1731,7 +1728,7 @@ static CURLcode setopt_cptr_proxy(struct Curl_easy *data, CURLoption option, */ #ifdef USE_SSL if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY)) - return Curl_setstropt(&s->str[STRING_SSL_PINNEDPUBLICKEY_PROXY], ptr); + return Curl_setstropt(data, STRING_SSL_PINNEDPUBLICKEY_PROXY, ptr); #endif return CURLE_NOT_BUILT_IN; @@ -1739,18 +1736,19 @@ static CURLcode setopt_cptr_proxy(struct Curl_easy *data, CURLoption option, /* * Set the client IP to send through HAProxy PROXY protocol */ - result = Curl_setstropt(&s->str[STRING_HAPROXY_CLIENT_IP], ptr); + result = Curl_setstropt(data, STRING_HAPROXY_CLIENT_IP, ptr); /* enable the HAProxy protocol if an IP is provided */ - s->haproxyprotocol = !!s->str[STRING_HAPROXY_CLIENT_IP]; + s->haproxyprotocol = !!CURL_EASY_STR(data, STRING_HAPROXY_CLIENT_IP); break; case CURLOPT_PROXY_CAINFO: /* * Set CA info SSL connection for proxy. Specify filename of the * CA certificate */ - result = Curl_setstropt(&s->str[STRING_SSL_CAFILE_PROXY], ptr); - s->proxy_ssl.custom_cafile = !!s->str[STRING_SSL_CAFILE_PROXY]; + result = Curl_setstropt(data, STRING_SSL_CAFILE_PROXY, ptr); + s->proxy_ssl.custom_cafile = + !!CURL_EASY_STR(data, STRING_SSL_CAFILE_PROXY); return result; case CURLOPT_PROXY_CRLFILE: /* @@ -1758,14 +1756,14 @@ static CURLcode setopt_cptr_proxy(struct Curl_easy *data, CURLoption option, * CRL to check certificates revocation */ if(Curl_ssl_supports(data, SSLSUPP_CRLFILE)) - return Curl_setstropt(&s->str[STRING_SSL_CRLFILE_PROXY], ptr); + return Curl_setstropt(data, STRING_SSL_CRLFILE_PROXY, ptr); return CURLE_NOT_BUILT_IN; case CURLOPT_PROXY_ISSUERCERT: /* * Set Issuer certificate file to check certificates issuer */ if(Curl_ssl_supports(data, SSLSUPP_ISSUERCERT)) - return Curl_setstropt(&s->str[STRING_SSL_ISSUERCERT_PROXY], ptr); + return Curl_setstropt(data, STRING_SSL_ISSUERCERT_PROXY, ptr); return CURLE_NOT_BUILT_IN; case CURLOPT_PROXY_CAPATH: /* @@ -1775,8 +1773,9 @@ static CURLcode setopt_cptr_proxy(struct Curl_easy *data, CURLoption option, #ifdef USE_SSL if(Curl_ssl_supports(data, SSLSUPP_CA_PATH)) { /* This does not work on Windows. */ - result = Curl_setstropt(&s->str[STRING_SSL_CAPATH_PROXY], ptr); - s->proxy_ssl.custom_capath = !!s->str[STRING_SSL_CAPATH_PROXY]; + result = Curl_setstropt(data, STRING_SSL_CAPATH_PROXY, ptr); + s->proxy_ssl.custom_capath = + !!CURL_EASY_STR(data, STRING_SSL_CAPATH_PROXY); return result; } #endif @@ -1799,8 +1798,16 @@ static CURLcode setopt_copypostfields(const char *ptr, struct UserDefined *s) CURLcode result = CURLE_OK; if(s->postfieldsize < -1) return CURLE_BAD_FUNCTION_ARGUMENT; - if(!ptr || s->postfieldsize == -1) - result = Curl_setstropt(&s->str[STRING_COPYPOSTFIELDS], ptr); + if(!ptr || s->postfieldsize == -1) { + if(ptr && (strlen(ptr) > CURL_MAX_INPUT_LENGTH)) + return CURLE_BAD_FUNCTION_ARGUMENT; + curlx_safefree(s->str_copypostfields); + if(ptr) { + s->str_copypostfields = curlx_strdup(ptr); + if(!s->str_copypostfields) + return CURLE_OUT_OF_MEMORY; + } + } else { size_t pflen = curlx_sotouz_range(s->postfieldsize, 0, SIZE_MAX); if(pflen == SIZE_MAX) @@ -1813,13 +1820,13 @@ static CURLcode setopt_copypostfields(const char *ptr, struct UserDefined *s) if(!p) return CURLE_OUT_OF_MEMORY; else { - curlx_free(s->str[STRING_COPYPOSTFIELDS]); - s->str[STRING_COPYPOSTFIELDS] = p; + curlx_free(s->str_copypostfields); + s->str_copypostfields = p; } } } - s->postfields = s->str[STRING_COPYPOSTFIELDS]; + s->postfields = s->str_copypostfields; s->method = HTTPREQ_POST; return result; } @@ -1847,12 +1854,12 @@ static CURLcode setopt_ech(struct Curl_easy *data, const char *ptr) else if(plen > 4 && !strncmp(ptr, "ecl:", 4)) { if(!s->tls_ech) s->tls_ech = CURLECH_HARD; - result = Curl_setstropt(&s->str[STRING_ECH_CONFIG], ptr + 4); + result = Curl_setstropt(data, STRING_ECH_CONFIG, ptr + 4); } else if(plen > 3 && !strncmp(ptr, "pn:", 3)) { if(!s->tls_ech) s->tls_ech = CURLECH_HARD; - result = Curl_setstropt(&s->str[STRING_ECH_PUBLIC], ptr + 3); + result = Curl_setstropt(data, STRING_ECH_PUBLIC, ptr + 3); } else result = CURLE_BAD_FUNCTION_ARGUMENT; @@ -1870,22 +1877,21 @@ static CURLcode setopt_cptr_ssl(struct Curl_easy *data, CURLoption option, char *ptr) { CURLcode result = CURLE_OK; - struct UserDefined *s = &data->set; switch(option) { case CURLOPT_KEYPASSWD: /* * String that holds the SSL or SSH private key password. */ - result = Curl_setstropt(&s->str[STRING_KEY_PASSWD], ptr); + result = Curl_setstropt(data, STRING_KEY_PASSWD, ptr); break; #ifdef USE_SSL case CURLOPT_CAINFO: /* * Set CA info for SSL connection. Specify filename of the CA certificate */ - result = Curl_setstropt(&s->str[STRING_SSL_CAFILE], ptr); - s->ssl.custom_cafile = !!s->str[STRING_SSL_CAFILE]; + result = Curl_setstropt(data, STRING_SSL_CAFILE, ptr); + data->set.ssl.custom_cafile = !!CURL_EASY_STR(data, STRING_SSL_CAFILE); return result; case CURLOPT_CAPATH: /* @@ -1894,8 +1900,8 @@ static CURLcode setopt_cptr_ssl(struct Curl_easy *data, CURLoption option, */ if(Curl_ssl_supports(data, SSLSUPP_CA_PATH)) { /* This does not work on Windows. */ - result = Curl_setstropt(&s->str[STRING_SSL_CAPATH], ptr); - s->ssl.custom_capath = !!s->str[STRING_SSL_CAPATH]; + result = Curl_setstropt(data, STRING_SSL_CAPATH, ptr); + data->set.ssl.custom_capath = !!CURL_EASY_STR(data, STRING_SSL_CAPATH); return result; } return CURLE_NOT_BUILT_IN; @@ -1905,18 +1911,18 @@ static CURLcode setopt_cptr_ssl(struct Curl_easy *data, CURLoption option, * to check certificates revocation */ if(Curl_ssl_supports(data, SSLSUPP_CRLFILE)) - return Curl_setstropt(&s->str[STRING_SSL_CRLFILE], ptr); + return Curl_setstropt(data, STRING_SSL_CRLFILE, ptr); return CURLE_NOT_BUILT_IN; case CURLOPT_SSL_CIPHER_LIST: if(Curl_ssl_supports(data, SSLSUPP_CIPHER_LIST)) /* set a list of cipher we want to use in the SSL connection */ - return Curl_setstropt(&s->str[STRING_SSL_CIPHER_LIST], ptr); + return Curl_setstropt(data, STRING_SSL_CIPHER_LIST, ptr); else return CURLE_NOT_BUILT_IN; case CURLOPT_TLS13_CIPHERS: if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) /* set preferred list of TLS 1.3 cipher suites */ - return Curl_setstropt(&s->str[STRING_SSL_CIPHER13_LIST], ptr); + return Curl_setstropt(data, STRING_SSL_CIPHER13_LIST, ptr); else return CURLE_NOT_BUILT_IN; case CURLOPT_RANDOM_FILE: @@ -1928,7 +1934,7 @@ static CURLcode setopt_cptr_ssl(struct Curl_easy *data, CURLoption option, * Set an SSL_CTX callback parameter pointer */ if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX)) { - s->ssl.fsslctxp = ptr; + data->set.ssl.fsslctxp = ptr; break; } else @@ -1937,28 +1943,28 @@ static CURLcode setopt_cptr_ssl(struct Curl_easy *data, CURLoption option, /* * String that holds filename of the SSL certificate to use */ - return Curl_setstropt(&s->str[STRING_CERT], ptr); + return Curl_setstropt(data, STRING_CERT, ptr); case CURLOPT_SSLCERTTYPE: /* * String that holds file type of the SSL certificate to use */ - return Curl_setstropt(&s->str[STRING_CERT_TYPE], ptr); + return Curl_setstropt(data, STRING_CERT_TYPE, ptr); case CURLOPT_SSLKEY: /* * String that holds filename of the SSL key to use */ - return Curl_setstropt(&s->str[STRING_KEY], ptr); + return Curl_setstropt(data, STRING_KEY, ptr); case CURLOPT_SSLKEYTYPE: /* * String that holds file type of the SSL key to use */ - return Curl_setstropt(&s->str[STRING_KEY_TYPE], ptr); + return Curl_setstropt(data, STRING_KEY_TYPE, ptr); case CURLOPT_SSLENGINE: /* * String that holds the SSL crypto engine. */ if(ptr && ptr[0]) { - result = Curl_setstropt(&s->str[STRING_SSL_ENGINE], ptr); + result = Curl_setstropt(data, STRING_SSL_ENGINE, ptr); if(!result) { result = Curl_ssl_set_engine(data, ptr); } @@ -1970,7 +1976,7 @@ static CURLcode setopt_cptr_ssl(struct Curl_easy *data, CURLoption option, * to check certificates issuer */ if(Curl_ssl_supports(data, SSLSUPP_ISSUERCERT)) - return Curl_setstropt(&s->str[STRING_SSL_ISSUERCERT], ptr); + return Curl_setstropt(data, STRING_SSL_ISSUERCERT, ptr); return CURLE_NOT_BUILT_IN; case CURLOPT_SSL_EC_CURVES: /* @@ -1978,7 +1984,7 @@ static CURLcode setopt_cptr_ssl(struct Curl_easy *data, CURLoption option, * Specify colon-delimited list of curve algorithm names. */ if(Curl_ssl_supports(data, SSLSUPP_SSL_EC_CURVES)) - return Curl_setstropt(&s->str[STRING_SSL_EC_CURVES], ptr); + return Curl_setstropt(data, STRING_SSL_EC_CURVES, ptr); return CURLE_NOT_BUILT_IN; case CURLOPT_SSL_SIGNATURE_ALGORITHMS: /* @@ -1986,7 +1992,7 @@ static CURLcode setopt_cptr_ssl(struct Curl_easy *data, CURLoption option, * Specify colon-delimited list of signature scheme names. */ if(Curl_ssl_supports(data, SSLSUPP_SIGNATURE_ALGORITHMS)) - return Curl_setstropt(&s->str[STRING_SSL_SIGNATURE_ALGORITHMS], ptr); + return Curl_setstropt(data, STRING_SSL_SIGNATURE_ALGORITHMS, ptr); return CURLE_NOT_BUILT_IN; case CURLOPT_PINNEDPUBLICKEY: /* @@ -1994,7 +2000,7 @@ static CURLcode setopt_cptr_ssl(struct Curl_easy *data, CURLoption option, * Specify filename of the public key in DER format. */ if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY)) - return Curl_setstropt(&s->str[STRING_SSL_PINNEDPUBLICKEY], ptr); + return Curl_setstropt(data, STRING_SSL_PINNEDPUBLICKEY, ptr); return CURLE_NOT_BUILT_IN; case CURLOPT_ECH: return setopt_ech(data, ptr); @@ -2023,7 +2029,7 @@ static CURLcode setopt_cptr_http_mqtt(struct Curl_easy *data, */ s->postfields = ptr; /* Release old copied data. */ - curlx_safefree(s->str[STRING_COPYPOSTFIELDS]); + curlx_safefree(s->str_copypostfields); s->method = HTTPREQ_POST; break; @@ -2043,15 +2049,13 @@ static CURLcode setopt_cptr_http_mqtt(struct Curl_easy *data, */ if(ptr && !*ptr) { ptr = Curl_get_content_encodings(); - if(ptr) { - curlx_free(s->str[STRING_ENCODING]); - s->str[STRING_ENCODING] = ptr; - } + if(ptr) + result = CURL_EASY_STR_SETN(data, STRING_ENCODING, ptr); else result = CURLE_OUT_OF_MEMORY; return result; } - return Curl_setstropt(&s->str[STRING_ENCODING], ptr); + return Curl_setstropt(data, STRING_ENCODING, ptr); #ifndef CURL_DISABLE_AWS case CURLOPT_AWS_SIGV4: @@ -2059,23 +2063,23 @@ static CURLcode setopt_cptr_http_mqtt(struct Curl_easy *data, * String that is merged to some authentication * parameters are used by the algorithm. */ - result = Curl_setstropt(&s->str[STRING_AWS_SIGV4], ptr); + result = Curl_setstropt(data, STRING_AWS_SIGV4, ptr); /* * Basic has been set by default; it needs to be unset here. */ - if(s->str[STRING_AWS_SIGV4]) + if(CURL_EASY_STR(data, STRING_AWS_SIGV4)) s->httpauth = CURLAUTH_AWS_SIGV4; break; #endif #ifndef CURL_DISABLE_HTTPSIG case CURLOPT_HTTPSIG_KEY: - result = Curl_setstropt(&s->str[STRING_HTTPSIG_KEY], ptr); + result = Curl_setstropt(data, STRING_HTTPSIG_KEY, ptr); break; case CURLOPT_HTTPSIG_KEYID: - result = Curl_setstropt(&s->str[STRING_HTTPSIG_KEYID], ptr); + result = Curl_setstropt(data, STRING_HTTPSIG_KEYID, ptr); break; case CURLOPT_HTTPSIG_HEADERS: - result = Curl_setstropt(&s->str[STRING_HTTPSIG_HEADERS], ptr); + result = Curl_setstropt(data, STRING_HTTPSIG_HEADERS, ptr); break; #endif case CURLOPT_REFERER: @@ -2083,21 +2087,21 @@ static CURLcode setopt_cptr_http_mqtt(struct Curl_easy *data, * String to set in the HTTP Referer: field. */ Curl_bufref_free(&data->state.referer); - result = Curl_setstropt(&s->str[STRING_SET_REFERER], ptr); + result = Curl_setstropt(data, STRING_SET_REFERER, ptr); break; case CURLOPT_USERAGENT: /* * String to use in the HTTP User-Agent field */ - return Curl_setstropt(&s->str[STRING_USERAGENT], ptr); + return Curl_setstropt(data, STRING_USERAGENT, ptr); #ifndef CURL_DISABLE_COOKIES case CURLOPT_COOKIE: /* * Cookie string to send to the remote server in the request. */ - return Curl_setstropt(&s->str[STRING_COOKIE], ptr); + return Curl_setstropt(data, STRING_COOKIE, ptr); case CURLOPT_COOKIEFILE: return cookiefile(data, ptr); @@ -2106,7 +2110,7 @@ static CURLcode setopt_cptr_http_mqtt(struct Curl_easy *data, /* * Set cookie filename to dump all cookies to when we are done. */ - result = Curl_setstropt(&s->str[STRING_COOKIEJAR], ptr); + result = Curl_setstropt(data, STRING_COOKIEJAR, ptr); if(!result) { /* * Activate the cookie parser. This may or may not already @@ -2143,12 +2147,12 @@ static CURLcode setopt_cptr_ssh(struct Curl_easy *data, CURLoption option, /* * Use this file instead of the $HOME/.ssh/id_dsa.pub file */ - return Curl_setstropt(&s->str[STRING_SSH_PUBLIC_KEY], ptr); + return Curl_setstropt(data, STRING_SSH_PUBLIC_KEY, ptr); case CURLOPT_SSH_PRIVATE_KEYFILE: /* * Use this file instead of the $HOME/.ssh/id_dsa file */ - return Curl_setstropt(&s->str[STRING_SSH_PRIVATE_KEY], ptr); + return Curl_setstropt(data, STRING_SSH_PRIVATE_KEY, ptr); case CURLOPT_SSH_KEYDATA: /* * Custom client data to pass to the SSH keyfunc callback @@ -2160,18 +2164,18 @@ static CURLcode setopt_cptr_ssh(struct Curl_easy *data, CURLoption option, * Option to allow for the MD5 of the host public key to be checked * for validation purposes. */ - return Curl_setstropt(&s->str[STRING_SSH_HOST_PUBLIC_KEY_MD5], ptr); + return Curl_setstropt(data, STRING_SSH_HOST_PUBLIC_KEY_MD5, ptr); case CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256: /* * Option to allow for the SHA256 of the host public key to be checked * for validation purposes. */ - return Curl_setstropt(&s->str[STRING_SSH_HOST_PUBLIC_KEY_SHA256], ptr); + return Curl_setstropt(data, STRING_SSH_HOST_PUBLIC_KEY_SHA256, ptr); case CURLOPT_SSH_KNOWNHOSTS: /* * Store the filename to read known hosts from. */ - return Curl_setstropt(&s->str[STRING_SSH_KNOWNHOSTS], ptr); + return Curl_setstropt(data, STRING_SSH_KNOWNHOSTS, ptr); #ifdef USE_LIBSSH2 case CURLOPT_SSH_HOSTKEYDATA: /* @@ -2198,15 +2202,15 @@ static CURLcode setopt_cptr_ftp(struct Curl_easy *data, CURLoption option, /* * Use FTP PORT, this also specifies which IP address to use */ - result = Curl_setstropt(&s->str[STRING_FTPPORT], ptr); - s->ftp_use_port = !!(s->str[STRING_FTPPORT]); + result = Curl_setstropt(data, STRING_FTPPORT, ptr); + s->ftp_use_port = !!CURL_EASY_STR(data, STRING_FTPPORT); break; case CURLOPT_FTP_ACCOUNT: - return Curl_setstropt(&s->str[STRING_FTP_ACCOUNT], ptr); + return Curl_setstropt(data, STRING_FTP_ACCOUNT, ptr); case CURLOPT_FTP_ALTERNATIVE_TO_USER: - return Curl_setstropt(&s->str[STRING_FTP_ALTERNATIVE_TO_USER], ptr); + return Curl_setstropt(data, STRING_FTP_ALTERNATIVE_TO_USER, ptr); case CURLOPT_KRBLEVEL: return CURLE_NOT_BUILT_IN; /* removed in 8.17.0 */ @@ -2226,44 +2230,41 @@ static CURLcode setopt_cptr_ftp(struct Curl_easy *data, CURLoption option, static CURLcode setopt_cptr_net(struct Curl_easy *data, CURLoption option, char *ptr) { - struct UserDefined *s = &data->set; switch(option) { case CURLOPT_INTERFACE: /* * Set what interface or address/hostname to bind the socket to when * performing an operation and thus what from-IP your connection will use. */ - return setstropt_interface(ptr, - &s->str[STRING_DEVICE], - &s->str[STRING_INTERFACE], - &s->str[STRING_BINDHOST]); + return setstropt_interface(data, ptr); + #ifdef USE_RESOLV_ARES case CURLOPT_DNS_SERVERS: - return Curl_setstropt(&s->str[STRING_DNS_SERVERS], ptr); + return Curl_setstropt(data, STRING_DNS_SERVERS, ptr); case CURLOPT_DNS_INTERFACE: - return Curl_setstropt(&s->str[STRING_DNS_INTERFACE], ptr); + return Curl_setstropt(data, STRING_DNS_INTERFACE, ptr); case CURLOPT_DNS_LOCAL_IP4: - return Curl_setstropt(&s->str[STRING_DNS_LOCAL_IP4], ptr); + return Curl_setstropt(data, STRING_DNS_LOCAL_IP4, ptr); case CURLOPT_DNS_LOCAL_IP6: - return Curl_setstropt(&s->str[STRING_DNS_LOCAL_IP6], ptr); + return Curl_setstropt(data, STRING_DNS_LOCAL_IP6, ptr); #endif #ifdef USE_UNIX_SOCKETS case CURLOPT_UNIX_SOCKET_PATH: - s->abstract_unix_socket = FALSE; - return Curl_setstropt(&s->str[STRING_UNIX_SOCKET_PATH], ptr); + data->set.abstract_unix_socket = FALSE; + return Curl_setstropt(data, STRING_UNIX_SOCKET_PATH, ptr); case CURLOPT_ABSTRACT_UNIX_SOCKET: - s->abstract_unix_socket = TRUE; - return Curl_setstropt(&s->str[STRING_UNIX_SOCKET_PATH], ptr); + data->set.abstract_unix_socket = TRUE; + return Curl_setstropt(data, STRING_UNIX_SOCKET_PATH, ptr); #endif #ifndef CURL_DISABLE_DOH case CURLOPT_DOH_URL: { - CURLcode result = Curl_setstropt(&s->str[STRING_DOH], ptr); - s->doh = !!(s->str[STRING_DOH]); + CURLcode result = Curl_setstropt(data, STRING_DOH, ptr); + data->set.doh = !!CURL_EASY_STR(data, STRING_DOH); return result; } #endif @@ -2280,19 +2281,19 @@ static CURLcode setopt_cptr_misc(struct Curl_easy *data, CURLoption option, switch(option) { case CURLOPT_REQUEST_TARGET: - return Curl_setstropt(&s->str[STRING_TARGET], ptr); + return Curl_setstropt(data, STRING_TARGET, ptr); #ifndef CURL_DISABLE_NETRC case CURLOPT_NETRC_FILE: - return Curl_setstropt(&s->str[STRING_NETRC_FILE], ptr); + return Curl_setstropt(data, STRING_NETRC_FILE, ptr); #endif case CURLOPT_CUSTOMREQUEST: - return Curl_setstropt(&s->str[STRING_CUSTOMREQUEST], ptr); + return Curl_setstropt(data, STRING_CUSTOMREQUEST, ptr); /* we do not set s->method = HTTPREQ_CUSTOM; here, we continue as if we were using the already set type and this changes the actual request keyword */ case CURLOPT_SERVICE_NAME: - return Curl_setstropt(&s->str[STRING_SERVICE_NAME], ptr); + return Curl_setstropt(data, STRING_SERVICE_NAME, ptr); case CURLOPT_HEADERDATA: s->writeheader = ptr; @@ -2334,27 +2335,40 @@ static CURLcode setopt_cptr_misc(struct Curl_easy *data, CURLoption option, s->errorbuffer = ptr; break; case CURLOPT_URL: - result = Curl_setstropt(&s->str[STRING_SET_URL], ptr); - Curl_bufref_set(&data->state.url, s->str[STRING_SET_URL], 0, NULL); + result = Curl_setstropt(data, STRING_SET_URL, ptr); + Curl_bufref_set(&data->state.url, + CURL_EASY_STR(data, STRING_SET_URL), 0, NULL); break; - case CURLOPT_USERPWD: - return setstropt_userpwd(ptr, &s->str[STRING_USERNAME], - &s->str[STRING_PASSWORD]); + case CURLOPT_USERPWD: { + char *u = NULL, *p = NULL; + result = setstropt_userpwd(ptr, &u, &p); + if(!result) { + result = CURL_EASY_STR_SETN(data, STRING_USERNAME, u); + u = NULL; + } + if(!result) { + result = CURL_EASY_STR_SETN(data, STRING_PASSWORD, p); + p = NULL; + } + curlx_free(u); + curlx_free(p); + return result; + } case CURLOPT_USERNAME: - return Curl_setstropt(&s->str[STRING_USERNAME], ptr); + return Curl_setstropt(data, STRING_USERNAME, ptr); case CURLOPT_PASSWORD: - return Curl_setstropt(&s->str[STRING_PASSWORD], ptr); + return Curl_setstropt(data, STRING_PASSWORD, ptr); case CURLOPT_LOGIN_OPTIONS: - return Curl_setstropt(&s->str[STRING_OPTIONS], ptr); + return Curl_setstropt(data, STRING_OPTIONS, ptr); case CURLOPT_XOAUTH2_BEARER: - return Curl_setstropt(&s->str[STRING_BEARER], ptr); + return Curl_setstropt(data, STRING_BEARER, ptr); case CURLOPT_RANGE: - return Curl_setstropt(&s->str[STRING_SET_RANGE], ptr); + return Curl_setstropt(data, STRING_SET_RANGE, ptr); case CURLOPT_PRIVATE: s->private_data = ptr; break; @@ -2382,25 +2396,25 @@ static CURLcode setopt_cptr_misc(struct Curl_easy *data, CURLoption option, break; case CURLOPT_DEFAULT_PROTOCOL: /* Set the protocol to use when the URL does not include any protocol */ - return Curl_setstropt(&s->str[STRING_DEFAULT_PROTOCOL], ptr); + return Curl_setstropt(data, STRING_DEFAULT_PROTOCOL, ptr); #ifndef CURL_DISABLE_SMTP case CURLOPT_MAIL_FROM: /* Set the SMTP mail originator */ - return Curl_setstropt(&s->str[STRING_MAIL_FROM], ptr); + return Curl_setstropt(data, STRING_MAIL_FROM, ptr); case CURLOPT_MAIL_AUTH: /* Set the SMTP auth originator */ - return Curl_setstropt(&s->str[STRING_MAIL_AUTH], ptr); + return Curl_setstropt(data, STRING_MAIL_AUTH, ptr); #endif case CURLOPT_SASL_AUTHZID: /* Authorization identity (identity to act as) */ - return Curl_setstropt(&s->str[STRING_SASL_AUTHZID], ptr); + return Curl_setstropt(data, STRING_SASL_AUTHZID, ptr); #ifndef CURL_DISABLE_RTSP case CURLOPT_RTSP_SESSION_ID: - return Curl_setstropt(&s->str[STRING_RTSP_SESSION_ID], ptr); + return Curl_setstropt(data, STRING_RTSP_SESSION_ID, ptr); case CURLOPT_RTSP_STREAM_URI: - return Curl_setstropt(&s->str[STRING_RTSP_STREAM_URI], ptr); + return Curl_setstropt(data, STRING_RTSP_STREAM_URI, ptr); case CURLOPT_RTSP_TRANSPORT: - return Curl_setstropt(&s->str[STRING_RTSP_TRANSPORT], ptr); + return Curl_setstropt(data, STRING_RTSP_TRANSPORT, ptr); case CURLOPT_INTERLEAVEDATA: s->rtp_out = ptr; break; @@ -2427,7 +2441,7 @@ static CURLcode setopt_cptr_misc(struct Curl_easy *data, CURLoption option, return CURLE_OUT_OF_MEMORY; } if(ptr) { - result = Curl_setstropt(&s->str[STRING_HSTS], ptr); + result = Curl_setstropt(data, STRING_HSTS, ptr); if(result) return result; /* this needs to build a list of filenames to read from, so that it can @@ -2459,7 +2473,7 @@ static CURLcode setopt_cptr_misc(struct Curl_easy *data, CURLoption option, if(!data->asi) return CURLE_OUT_OF_MEMORY; } - result = Curl_setstropt(&s->str[STRING_ALTSVC], ptr); + result = Curl_setstropt(data, STRING_ALTSVC, ptr); if(result) break; if(ptr) @@ -2719,10 +2733,9 @@ static CURLcode setopt_offt(struct Curl_easy *data, CURLoption option, if(offt < -1) return CURLE_BAD_FUNCTION_ARGUMENT; - if(s->postfieldsize < offt && - s->postfields == s->str[STRING_COPYPOSTFIELDS]) { + if(s->postfieldsize < offt && s->str_copypostfields) { /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */ - curlx_safefree(s->str[STRING_COPYPOSTFIELDS]); + curlx_safefree(s->str_copypostfields); s->postfields = NULL; } s->postfieldsize = offt; diff --git a/lib/setopt.h b/lib/setopt.h index c421f5c5e5..e386262f88 100644 --- a/lib/setopt.h +++ b/lib/setopt.h @@ -31,7 +31,8 @@ CURLcode Curl_setopt_SSLVERSION(struct Curl_easy *data, CURLoption option, #define Curl_setopt_SSLVERSION(a, b, c) CURLE_NOT_BUILT_IN #endif -CURLcode Curl_setstropt(char **charp, const char *s) WARN_UNUSED_RESULT; +CURLcode Curl_setstropt(struct Curl_easy *data, + enum dupstring id, const char *s) WARN_UNUSED_RESULT; CURLcode Curl_setblobopt(struct curl_blob **blobp, const struct curl_blob *blob) WARN_UNUSED_RESULT; CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) diff --git a/lib/smtp.c b/lib/smtp.c index c01151e455..fbbac28327 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -207,7 +207,7 @@ static CURLcode smtp_parse_custom_request(struct Curl_easy *data, struct SMTP *smtp) { CURLcode result = CURLE_OK; - const char *custom = data->set.str[STRING_CUSTOMREQUEST]; + const char *custom = CURL_EASY_STR(data, STRING_CUSTOMREQUEST); /* URL decode the custom request */ if(custom) @@ -912,6 +912,7 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data, char *from = NULL; char *auth = NULL; char *size = NULL; + const char *str; CURLcode result = CURLE_OK; /* We notify the server we are sending UTF-8 data if a) it supports the @@ -921,15 +922,15 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data, bool utf8 = FALSE; /* Calculate the FROM parameter */ - if(data->set.str[STRING_MAIL_FROM]) { + str = CURL_EASY_STR(data, STRING_MAIL_FROM); + if(str) { char *address = NULL; struct hostname host = { NULL, NULL, NULL, NULL }; const char *suffix = ""; /* Parse the FROM mailbox into the local address and hostname parts, converting the hostname to an IDN A-label if necessary */ - result = smtp_parse_address(data, data->set.str[STRING_MAIL_FROM], - &address, &host, &suffix); + result = smtp_parse_address(data, str, &address, &host, &suffix); if(result) goto out; @@ -962,16 +963,16 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data, } /* Calculate the optional AUTH parameter */ - if(data->set.str[STRING_MAIL_AUTH] && smtpc->sasl.authused) { - if(data->set.str[STRING_MAIL_AUTH][0] != '\0') { + str = CURL_EASY_STR(data, STRING_MAIL_AUTH); + if(str && smtpc->sasl.authused) { + if(str[0] != '\0') { char *address = NULL; struct hostname host = { NULL, NULL, NULL, NULL }; const char *suffix = ""; /* Parse the AUTH mailbox into the local address and hostname parts, converting the hostname to an IDN A-label if necessary */ - result = smtp_parse_address(data, data->set.str[STRING_MAIL_AUTH], - &address, &host, &suffix); + result = smtp_parse_address(data, str, &address, &host, &suffix); if(result) goto out; diff --git a/lib/transfer.c b/lib/transfer.c index acab3e1edb..1e7f3cd1e5 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -451,7 +451,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) * By resetting it here, we ensure each new request starts fresh. */ data->state.retrycount = 0; - if(!data->set.str[STRING_SET_URL] && !data->set.uh) { + if(!CURL_EASY_STR(data, STRING_SET_URL) && !data->set.uh) { /* we cannot do anything without URL */ failf(data, "No URL set"); return CURLE_URL_MALFORMAT; @@ -460,19 +460,22 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) /* CURLOPT_CURLU overrides CURLOPT_URL and the contents of the CURLU handle is allowed to be changed by the user between transfers */ if(data->set.uh) { + char *url = NULL; CURLUcode uc; - curlx_free(data->set.str[STRING_SET_URL]); - uc = curl_url_get(data->set.uh, - CURLUPART_URL, &data->set.str[STRING_SET_URL], 0); + uc = curl_url_get(data->set.uh, CURLUPART_URL, &url, 0); if(uc) { /* clear the pointer to not point to freed memory anymore */ Curl_bufref_set(&data->state.url, NULL, 0, NULL); failf(data, "No URL set"); return CURLE_URL_MALFORMAT; } + result = CURL_EASY_STR_SETN(data, STRING_SET_URL, url); + if(result) + return result; } - Curl_bufref_set(&data->state.url, data->set.str[STRING_SET_URL], 0, NULL); + Curl_bufref_set(&data->state.url, CURL_EASY_STR(data, STRING_SET_URL), + 0, NULL); if(data->set.postfields && data->set.set_resume_from) { /* we cannot */ @@ -505,9 +508,9 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) Curl_data_priority_clear_state(data); if(data->set.http_auto_referer) Curl_bufref_free(&data->state.referer); - if(data->set.str[STRING_SET_REFERER]) - Curl_bufref_set(&data->state.referer, data->set.str[STRING_SET_REFERER], - 0, NULL); + if(CURL_EASY_STR(data, STRING_SET_REFERER)) + Curl_bufref_set(&data->state.referer, + CURL_EASY_STR(data, STRING_SET_REFERER), 0, NULL); else Curl_bufref_free(&data->state.referer); diff --git a/lib/uint-hashset.c b/lib/uint-hashset.c new file mode 100644 index 0000000000..fabc0aee9c --- /dev/null +++ b/lib/uint-hashset.c @@ -0,0 +1,305 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , 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.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. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#include "uint-hashset.h" + +/* random patterns for API verification */ +#ifdef DEBUGBUILD +#define CURL_U8_STRSET_MAGIC 0x7117e783 +#endif + +#define CURL_U8_STRSET_DEBUG 0 + +#define CURL_SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b))) + +static const uint8_t u8_smask[] = { + 0x00U, + 0x01U, + 0x03U, + 0x07U, + 0x0FU, + 0x1FU, + 0x3FU, + 0x7FU, + 0xFFU, +}; + +#define CURL_U8_SET_SLOT_IDX(s, i) (uint8_t)((i) & u8_smask[(s)->slotbits]) +#define CURL_U8_SLOT_CNT(i) ((uint16_t)u8_smask[(i)] + 1) +#define CURL_U8_SET_SLOT_CNT(s) CURL_U8_SLOT_CNT((s)->slotbits) + +/* A hashset for tuples (id, string) using Robin Hood Hashing. + * + * The basic idea here to handle collisions by robbing "rich" entries and + * giving to the "poor": + * - We have an array: (id, string) are ideally placed at index "id % size". + * - If slot at index is already occupied, we have a collision. + * - A simple collision strategy would look at the next index, and the + * next until until finding an empty slot. + * - The drawback is that this may lead to many checks on lookups, as it + * will need to also look at subsequent slots until it finds the match. + * The amount of lookups is the "probe sequence length" (psl) and this + * may vary greatly between entries. + * - Robin Hood Hashing balances the 'psl's of all entries more evenly: + * - psl == 0 means an entry is in exactly the right slot + * - pasl == 1 means it is in the slot right after. psl == 2 is the slot + * after that, etc. + * - when inserting a new entry, track its psl. Finding a slot where + * the existing entry has a lower psl makes a swap. Put the new entry + * and its psl there, take the previous entry and its psl and find + * the next best slot for the previous entry. */ +void Curl_u8_strset_init(struct u8_strset *set) +{ +#if defined(__GNUC__) && __GNUC__ >= 13 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" +#endif + memset(set, 0, sizeof(*set)); +#if defined(__GNUC__) && __GNUC__ >= 13 +#pragma GCC diagnostic pop +#endif + set->data = set->sdata; + set->ids = set->sids; + set->psl = set->spsl; + set->slotbits = CURL_U8_STRSET_START_BITS; + set->count = 0; +#ifdef DEBUGBUILD + set->init = CURL_U8_STRSET_MAGIC; +#endif +} + +void Curl_u8_strset_clear(struct u8_strset *set) +{ + uint16_t i; + DEBUGASSERT(set->init == CURL_U8_STRSET_MAGIC); + for(i = 0; i < CURL_U8_SET_SLOT_CNT(set); ++i) + curlx_safefree(set->data[i]); + + if(set->data != set->sdata) + curlx_safefree(set->data); + Curl_u8_strset_init(set); +} + +static void u8_strset_addn(struct u8_strset *set, uint8_t id, char *val) +{ + uint8_t i = CURL_U8_SET_SLOT_IDX(set, id); + uint8_t psl = 0; + while(set->data[i]) { + if(psl > set->psl[i]) { /* SWAP */ + char *tmpdata; + tmpdata = set->data[i]; + set->data[i] = val; + val = tmpdata; + CURL_SWAP(set->psl[i], psl); + CURL_SWAP(set->ids[i], id); + } + i = CURL_U8_SET_SLOT_IDX(set, i + 1); + ++psl; + } + set->ids[i] = id; + set->data[i] = val; + set->psl[i] = psl; + ++set->count; +} + +static bool u8_strset_grow(struct u8_strset *set) +{ + uint8_t i, *prev_ids, nslotbits; + uint16_t prev_slots; + char **prev_data; + size_t nslots; + void *d; + + if(set->slotbits >= 8) + return FALSE; + nslotbits = (uint8_t)(set->slotbits + 1); +#if CURL_U8_STRSET_DEBUG + curl_mfprintf(stderr, "u8_strset_grow from %d to %d\n", + set->slotbits, nslotbits); +#endif + nslots = CURL_U8_SLOT_CNT(nslotbits); + d = curlx_calloc(1, (nslots * sizeof(char *)) + (2 * nslots)); + if(!d) + return FALSE; + + prev_data = set->data; + prev_ids = set->ids; + prev_slots = set->slotbits; +#if defined(__GNUC__) && __GNUC__ >= 13 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wanalyzer-allocation-size" +#endif + set->data = (char **)d; +#if defined(__GNUC__) && __GNUC__ >= 13 +#pragma GCC diagnostic pop +#endif + set->ids = (uint8_t *)d + (nslots * sizeof(char *)); + set->psl = set->ids + nslots; + set->slotbits = nslotbits; + set->count = 0; + /* re-add previous entries */ + for(i = 0; i < CURL_U8_SLOT_CNT(prev_slots); ++i) { + if(prev_data[i]) + u8_strset_addn(set, prev_ids[i], prev_data[i]); + } + if(prev_data != set->sdata) + curlx_free(prev_data); + return TRUE; +} + +static bool u8_strset_get_index(struct u8_strset *set, + uint8_t id, uint8_t *pindex) +{ + uint8_t i = CURL_U8_SET_SLOT_IDX(set, id); + uint8_t psl = 0; + while(set->data[i] && (psl <= set->psl[i])) { + if(set->ids[i] == id) { + *pindex = i; +#if CURL_U8_STRSET_DEBUG + curl_mfprintf(stderr, "u8_strset_index %d=%s\n", id, set->data[i]); +#endif + return TRUE; + } + i = CURL_U8_SET_SLOT_IDX(set, i + 1); + ++psl; + } +#if CURL_U8_STRSET_DEBUG + curl_mfprintf(stderr, "u8_strset_index %d not found\n", id); +#endif + *pindex = 0; + return FALSE; +} + +uint16_t Curl_u8_strset_count(struct u8_strset *set) +{ + return set->count; +} + +const char *Curl_u8_strset_get(struct u8_strset *set, uint8_t id) +{ + uint8_t i; + DEBUGASSERT(set->init == CURL_U8_STRSET_MAGIC); + if(u8_strset_get_index(set, id, &i)) + return set->data[i]; + return NULL; +} + +CURLcode Curl_u8_strset_setn(struct u8_strset *set, + uint8_t id, char *str) +{ + uint8_t i; + + DEBUGASSERT(set->init == CURL_U8_STRSET_MAGIC); +#if CURL_U8_STRSET_DEBUG + curl_mfprintf(stderr, "u8_strset_setn %d=%s\n", id, str); +#endif + if(!str) { + Curl_u8_strset_unset(set, id); + return CURLE_OK; + } + + if(u8_strset_get_index(set, id, &i)) { + /* `id` is in set, replace value */ + curlx_free(set->data[i]); + set->data[i] = str; + return CURLE_OK; + } + /* `id` not in set yet, grow if full */ + if((set->count >= CURL_U8_SET_SLOT_CNT(set)) && !u8_strset_grow(set)) { + curlx_free(str); + return CURLE_OUT_OF_MEMORY; + } + + u8_strset_addn(set, id, str); + return CURLE_OK; +} + + +CURLcode Curl_u8_strset_set(struct u8_strset *set, + uint8_t id, const char *str) +{ + char *val; + + DEBUGASSERT(set->init == CURL_U8_STRSET_MAGIC); + if(!str) { + Curl_u8_strset_unset(set, id); + return CURLE_OK; + } + + val = curlx_strdup(str); + if(!val) + return CURLE_OUT_OF_MEMORY; + return Curl_u8_strset_setn(set, id, val); +} + +static void u8_strset_unset(struct u8_strset *set, uint8_t id, bool zero) +{ + uint8_t i, j; + + DEBUGASSERT(set->init == CURL_U8_STRSET_MAGIC); + if(u8_strset_get_index(set, id, &i)) { + /* `id` is in set */ + if(zero) + curlx_strzero(set->data[i]); + curlx_safefree(set->data[i]); + set->ids[i] = set->psl[i] = 0; + --set->count; + j = CURL_U8_SET_SLOT_IDX(set, i + 1); + /* shift all entries with positive psl "down" */ + while(set->data[j] && set->psl[j]) { + set->data[i] = set->data[j]; + set->ids[i] = set->ids[j]; + set->psl[i] = (uint8_t)(set->psl[j] - 1); + set->data[j] = NULL; + set->ids[j] = set->psl[j] = 0; + i = j; + j = CURL_U8_SET_SLOT_IDX(set, i + 1); + } + } +} + +void Curl_u8_strset_unset(struct u8_strset *set, uint8_t id) +{ + u8_strset_unset(set, id, FALSE); +} + +void Curl_u8_strset_unset0(struct u8_strset *set, uint8_t id) +{ + u8_strset_unset(set, id, TRUE); +} + +CURLcode Curl_u8_strset_copy(struct u8_strset *dest, struct u8_strset *src) +{ + CURLcode result = CURLE_OK; + uint16_t i; + + DEBUGASSERT(src->init == CURL_U8_STRSET_MAGIC); + Curl_u8_strset_clear(dest); + for(i = 0; !result && (i < CURL_U8_SET_SLOT_CNT(src)); ++i) { + if(src->data[i]) + result = Curl_u8_strset_set(dest, src->ids[i], src->data[i]); + } + return result; +} diff --git a/lib/uint-hashset.h b/lib/uint-hashset.h new file mode 100644 index 0000000000..48622ae427 --- /dev/null +++ b/lib/uint-hashset.h @@ -0,0 +1,80 @@ +#ifndef HEADER_CURL_UINT_HASHSET_H +#define HEADER_CURL_UINT_HASHSET_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , 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.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. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +/* How large should the initial set be? + * Measuring our test suite with set growth force fail, gives + * BITS RESULT + * 1 1261 tests out of 1951 reported OK: 64% + * 2 1792 tests out of 1951 reported OK: 91% + * 3 1944 tests out of 1951 reported OK: 99% + * 4 1949 tests out of 1951 reported OK: 99% + * 5 single fail of 3211, unit test for u8_strset + * meaning 91% of our tests to not set more than 4 strings and + * 99% do not set more than 8. + */ +#define CURL_U8_STRSET_START_BITS 2 +#define CURL_U8_STRSET_START_DIM (1U << CURL_U8_STRSET_START_BITS) + +/* A set that can hold up to 256 strings identified by an `id'. + * Setting a string for an existing id replaces the previous one. + * Getting the string for an id not in the set returns NULL. + * Setting an id to NULL unsets the id. + */ +struct u8_strset { + char **data; /* #slots array of null-terminated strings */ + uint8_t *ids; /* #slots array of `id` values */ + uint8_t *psl; /* #slots array of "probe sequence length" values */ + char *sdata[CURL_U8_STRSET_START_DIM]; + uint8_t sids[CURL_U8_STRSET_START_DIM]; + uint8_t spsl[CURL_U8_STRSET_START_DIM]; + uint16_t count; + uint8_t slotbits; +#ifdef DEBUGBUILD + int32_t init; +#endif +}; + +void Curl_u8_strset_init(struct u8_strset *set); +void Curl_u8_strset_clear(struct u8_strset *set); + +uint16_t Curl_u8_strset_count(struct u8_strset *set); +const char *Curl_u8_strset_get(struct u8_strset *set, uint8_t id); + +/* Set string for id, makes a copy. */ +CURLcode Curl_u8_strset_set(struct u8_strset *set, + uint8_t id, const char *str); +/* Set string for id, takes ownership of `str` even on failure. */ +CURLcode Curl_u8_strset_setn(struct u8_strset *set, + uint8_t id, char *str); +void Curl_u8_strset_unset(struct u8_strset *set, uint8_t id); + +/* Remove the string if in the set and zero its memory */ +void Curl_u8_strset_unset0(struct u8_strset *set, uint8_t id); + +CURLcode Curl_u8_strset_copy(struct u8_strset *dest, struct u8_strset *src); + +#endif /* HEADER_CURL_UINT_HASHSET_H */ diff --git a/lib/url.c b/lib/url.c index 0b2d414526..16e14aaac0 100644 --- a/lib/url.c +++ b/lib/url.c @@ -148,21 +148,17 @@ static curl_prot_t get_protocol_family(const struct Curl_scheme *s) void Curl_freeset(struct Curl_easy *data) { /* Free all dynamic strings stored in the data->set substructure. */ - enum dupstring i; enum dupblob j; - for(i = (enum dupstring)0; i < STRING_LAST; i++) { - if(i == STRING_PASSWORD || - i == STRING_KEY_PASSWD || + CURL_EASY_STR_CLEAR0(data, STRING_PASSWORD); + CURL_EASY_STR_CLEAR0(data, STRING_KEY_PASSWD); + CURL_EASY_STR_CLEAR0(data, STRING_BEARER); #ifndef CURL_DISABLE_PROXY - i == STRING_PROXYPASSWORD || - i == STRING_KEY_PASSWD_PROXY || + CURL_EASY_STR_CLEAR0(data, STRING_PROXYPASSWORD); + CURL_EASY_STR_CLEAR0(data, STRING_KEY_PASSWD_PROXY); #endif - i == STRING_BEARER) { - curlx_strzero(data->set.str[i]); - } - curlx_safefree(data->set.str[i]); - } + Curl_u8_strset_clear(&data->set.strings); + curlx_safefree(data->set.str_copypostfields); for(j = (enum dupblob)0; j < BLOB_LAST; j++) { curlx_safefree(data->set.blobs[j]); @@ -257,11 +253,11 @@ CURLcode Curl_close(struct Curl_easy **datap) curlx_dyn_free(&data->state.headerb); Curl_flush_cookies(data, TRUE); #ifndef CURL_DISABLE_ALTSVC - Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]); + Curl_altsvc_save(data, data->asi, CURL_EASY_STR(data, STRING_ALTSVC)); Curl_altsvc_cleanup(&data->asi); #endif #ifndef CURL_DISABLE_HSTS - Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]); + Curl_hsts_save(data, data->hsts, CURL_EASY_STR(data, STRING_HSTS)); if(!data->share || !data->share->hsts) Curl_hsts_cleanup(&data->hsts); curl_slist_free_all(data->state.hstslist); /* clean up list */ @@ -321,6 +317,8 @@ void Curl_init_userdefined(struct Curl_easy *data) set->in_set = stdin; /* default input from stdin */ set->err = stderr; /* default stderr to stderr */ + Curl_u8_strset_init(&data->set.strings); + #if defined(__clang__) && __clang_major__ >= 16 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wcast-function-type-strict" @@ -475,6 +473,8 @@ CURLcode Curl_open(struct Curl_easy **curl) Curl_hash_init(&data->meta_hash, 23, Curl_hash_str, curlx_str_key_compare, easy_meta_freeentry); + DEBUGASSERT(STRING_LAST <= UINT8_MAX); + Curl_u8_strset_init(&data->set.strings); curlx_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER); Curl_bufref_init(&data->state.url); Curl_bufref_init(&data->state.referer); @@ -1228,8 +1228,8 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->transport_wanted = TRNSPRT_TCP; /* most of them are TCP streams */ /* Store the local bind parameters that will be used for this connection */ - if(data->set.str[STRING_DEVICE]) { - conn->localdev = curlx_strdup(data->set.str[STRING_DEVICE]); + if(CURL_EASY_STR(data, STRING_DEVICE)) { + conn->localdev = curlx_strdup(CURL_EASY_STR(data, STRING_DEVICE)); if(!conn->localdev) goto error; } @@ -1384,7 +1384,7 @@ static CURLcode url_set_data_creds_netrc(struct Curl_easy *data, ret = Curl_netrc_scan(data, &data->state.netrc, data->state.origin->hostname, Curl_creds_user(ncreds_in), - data->set.str[STRING_NETRC_FILE], + CURL_EASY_STR(data, STRING_NETRC_FILE), &ncreds_out); DEBUGASSERT(!ret || !ncreds_out); if(ret == NETRC_OUT_OF_MEMORY) { @@ -1395,8 +1395,8 @@ static CURLcode url_set_data_creds_netrc(struct Curl_easy *data, (data->set.use_netrc == CURL_NETRC_OPTIONAL))) { infof(data, "Could not find host %s in the %s file; using defaults", data->state.origin->hostname, - (data->set.str[STRING_NETRC_FILE] ? - data->set.str[STRING_NETRC_FILE] : ".netrc")); + (CURL_EASY_STR(data, STRING_NETRC_FILE) ? + CURL_EASY_STR(data, STRING_NETRC_FILE) : ".netrc")); } else if(ret) { const char *m = Curl_netrc_strerror(ret); @@ -1450,17 +1450,17 @@ static CURLcode url_set_data_creds(struct Curl_easy *data, CURLU *uh) struct Curl_creds *newcreds = NULL; CURLcode result = CURLE_OK; - if((data->set.str[STRING_USERNAME] || - data->set.str[STRING_PASSWORD] || - data->set.str[STRING_BEARER] || - data->set.str[STRING_SASL_AUTHZID] || - data->set.str[STRING_SERVICE_NAME]) && + if((CURL_EASY_STR(data, STRING_USERNAME) || + CURL_EASY_STR(data, STRING_PASSWORD) || + CURL_EASY_STR(data, STRING_BEARER) || + CURL_EASY_STR(data, STRING_SASL_AUTHZID) || + CURL_EASY_STR(data, STRING_SERVICE_NAME)) && Curl_auth_allowed_to_origin(data, data->state.origin)) { - result = Curl_creds_create(data->set.str[STRING_USERNAME], - data->set.str[STRING_PASSWORD], - data->set.str[STRING_BEARER], - data->set.str[STRING_SASL_AUTHZID], - data->set.str[STRING_SERVICE_NAME], + result = Curl_creds_create(CURL_EASY_STR(data, STRING_USERNAME), + CURL_EASY_STR(data, STRING_PASSWORD), + CURL_EASY_STR(data, STRING_BEARER), + CURL_EASY_STR(data, STRING_SASL_AUTHZID), + CURL_EASY_STR(data, STRING_SERVICE_NAME), CREDS_OPTION, &newcreds); if(result) goto out; @@ -1547,8 +1547,8 @@ static CURLcode url_set_conn_origin_etc(struct Curl_easy *data, goto out; /* set the connection options */ - if(data->set.str[STRING_OPTIONS]) { - conn->options = curlx_strdup(data->set.str[STRING_OPTIONS]); + if(CURL_EASY_STR(data, STRING_OPTIONS)) { + conn->options = curlx_strdup(CURL_EASY_STR(data, STRING_OPTIONS)); if(!conn->options) { result = CURLE_OUT_OF_MEMORY; goto out; @@ -1579,14 +1579,14 @@ static CURLcode setup_range(struct Curl_easy *data) { struct UrlState *s = &data->state; s->resume_from = data->set.set_resume_from; - if(s->resume_from || data->set.str[STRING_SET_RANGE]) { + if(s->resume_from || CURL_EASY_STR(data, STRING_SET_RANGE)) { if(s->rangestringalloc) curlx_free(s->range); if(s->resume_from) s->range = curl_maprintf("%" FMT_OFF_T "-", s->resume_from); else - s->range = curlx_strdup(data->set.str[STRING_SET_RANGE]); + s->range = curlx_strdup(CURL_EASY_STR(data, STRING_SET_RANGE)); if(!s->range) return CURLE_OUT_OF_MEMORY; @@ -2052,11 +2052,10 @@ static CURLcode url_create_needle(struct Curl_easy *data, /************************************************************* * Set UDS first. It overrides "via_peer" and proxy settings. *************************************************************/ - if(network_scheme && data->set.str[STRING_UNIX_SOCKET_PATH]) { - result = Curl_peer_uds_create(needle->origin->scheme, - data->set.str[STRING_UNIX_SOCKET_PATH], - (bool)data->set.abstract_unix_socket, - &needle->via_peer); + if(network_scheme && CURL_EASY_STR(data, STRING_UNIX_SOCKET_PATH)) { + result = Curl_peer_uds_create( + needle->origin->scheme, CURL_EASY_STR(data, STRING_UNIX_SOCKET_PATH), + (bool)data->set.abstract_unix_socket, &needle->via_peer); if(result) goto out; } @@ -2169,10 +2168,10 @@ static CURLcode url_set_data_origin_and_creds(struct Curl_easy *data) /* Calculate the *real* URL this transfer uses, applying defaults * where information is missing. */ - if(data->set.str[STRING_DEFAULT_PROTOCOL] && + if(CURL_EASY_STR(data, STRING_DEFAULT_PROTOCOL) && !Curl_is_absolute_url(Curl_bufref_ptr(&data->state.url), NULL, 0, TRUE)) { char *url = curl_maprintf("%s://%s", - data->set.str[STRING_DEFAULT_PROTOCOL], + CURL_EASY_STR(data, STRING_DEFAULT_PROTOCOL), Curl_bufref_ptr(&data->state.url)); if(!url) { result = CURLE_OUT_OF_MEMORY; diff --git a/lib/urldata.h b/lib/urldata.h index f0c6d7ae1b..8bb8287179 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -69,6 +69,7 @@ #include "request.h" #include "ratelimit.h" #include "netrc.h" +#include "uint-hashset.h" #include "vdns/asyn.h" #include "vdns/hostip.h" #include "vtls/vtls_config.h" @@ -804,14 +805,6 @@ enum dupstring { STRING_ECH_PUBLIC, /* CURLOPT_ECH_PUBLIC */ STRING_SSL_SIGNATURE_ALGORITHMS, /* CURLOPT_SSL_SIGNATURE_ALGORITHMS */ - /* -- end of null-terminated strings -- */ - - STRING_LASTZEROTERMINATED, - - /* -- below this are pointers to binary data that cannot be strdup'ed. --- */ - - STRING_COPYPOSTFIELDS, /* if POST, set the fields' values here */ - STRING_LAST /* not used, an end-of-list marker */ }; @@ -839,6 +832,7 @@ struct UserDefined { uint32_t httpauth; /* kind of HTTP authentication to use (bitmask) */ uint32_t proxyauth; /* kind of proxy authentication to use (bitmask) */ void *postfields; /* if POST, set the fields' values here */ + char *str_copypostfields; /* CURLOPT_COPYPOSTFIELDS value */ curl_seek_callback seek_func; /* function that seeks the input */ curl_off_t postfieldsize; /* if POST, this might have a size to use instead of strlen(), and then the data *may* be binary @@ -933,7 +927,7 @@ struct UserDefined { uint32_t ssh_auth_types; /* allowed SSH auth types */ uint32_t new_directory_perms; /* when creating remote dirs */ #endif - char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */ + struct u8_strset strings; struct curl_blob *blobs[BLOB_LAST]; uint32_t new_file_perms; /* when creating remote files */ #ifdef USE_IPV6 @@ -1230,6 +1224,17 @@ struct Curl_easy { valid after a client has asked for it */ }; +#define CURL_EASY_STR(d, id) \ + Curl_u8_strset_get(&(d)->set.strings, (uint8_t)(id)) +#define CURL_EASY_STR_SET(d, id, s) \ + Curl_u8_strset_set(&(d)->set.strings, (uint8_t)(id), (s)) +#define CURL_EASY_STR_SETN(d, id, s) \ + Curl_u8_strset_setn(&(d)->set.strings, (uint8_t)(id), (s)) +#define CURL_EASY_STR_CLEAR(d, id) \ + Curl_u8_strset_unset(&(d)->set.strings, (uint8_t)(id)) +#define CURL_EASY_STR_CLEAR0(d, id) \ + Curl_u8_strset_unset0(&(d)->set.strings, (uint8_t)(id)) + #define LIBCURL_NAME "libcurl" #endif /* HEADER_CURL_URLDATA_H */ diff --git a/lib/vdns/asyn-ares.c b/lib/vdns/asyn-ares.c index 7d27c7fc8d..a98c4de756 100644 --- a/lib/vdns/asyn-ares.c +++ b/lib/vdns/asyn-ares.c @@ -660,7 +660,7 @@ static CURLcode async_ares_set_dns_servers(struct Curl_easy *data, { struct async_ares_ctx *ares = async ? &async->ares : NULL; CURLcode result = CURLE_NOT_BUILT_IN; - const char *servers = data->set.str[STRING_DNS_SERVERS]; + const char *servers = CURL_EASY_STR(data, STRING_DNS_SERVERS); int ares_result = ARES_SUCCESS; #ifdef DEBUGBUILD @@ -696,7 +696,7 @@ static CURLcode async_ares_set_dns_interface(struct Curl_easy *data, struct Curl_resolv_async *async) { struct async_ares_ctx *ares = async ? &async->ares : NULL; - const char *interf = data->set.str[STRING_DNS_INTERFACE]; + const char *interf = CURL_EASY_STR(data, STRING_DNS_INTERFACE); if(!interf) interf = ""; @@ -713,7 +713,7 @@ static CURLcode async_ares_set_dns_local_ip4(struct Curl_easy *data, { struct async_ares_ctx *ares = async ? &async->ares : NULL; struct in_addr a4; - const char *local_ip4 = data->set.str[STRING_DNS_LOCAL_IP4]; + const char *local_ip4 = CURL_EASY_STR(data, STRING_DNS_LOCAL_IP4); if(!local_ip4 || (local_ip4[0] == 0)) { a4.s_addr = 0; /* disabled: do not bind to a specific address */ @@ -738,7 +738,7 @@ static CURLcode async_ares_set_dns_local_ip6(struct Curl_easy *data, #ifdef USE_IPV6 struct async_ares_ctx *ares = async ? &async->ares : NULL; unsigned char a6[INET6_ADDRSTRLEN]; - const char *local_ip6 = data->set.str[STRING_DNS_LOCAL_IP6]; + const char *local_ip6 = CURL_EASY_STR(data, STRING_DNS_LOCAL_IP6); if(!local_ip6 || (local_ip6[0] == 0)) { /* disabled: do not bind to a specific address */ diff --git a/lib/vdns/doh.c b/lib/vdns/doh.c index fe6f9a8907..3b89cb9620 100644 --- a/lib/vdns/doh.c +++ b/lib/vdns/doh.c @@ -336,17 +336,20 @@ static CURLcode doh_probe_run(struct Curl_easy *data, doh->set.ssl.custom_cafile = data->set.ssl.custom_cafile; doh->set.ssl.custom_capath = data->set.ssl.custom_capath; doh->set.ssl.custom_cablob = data->set.ssl.custom_cablob; - if(data->set.str[STRING_SSL_CAFILE]) { - ERROR_CHECK_SETOPT(CURLOPT_CAINFO, data->set.str[STRING_SSL_CAFILE]); + if(CURL_EASY_STR(data, STRING_SSL_CAFILE)) { + ERROR_CHECK_SETOPT(CURLOPT_CAINFO, + CURL_EASY_STR(data, STRING_SSL_CAFILE)); } if(data->set.blobs[BLOB_CAINFO]) { ERROR_CHECK_SETOPT(CURLOPT_CAINFO_BLOB, data->set.blobs[BLOB_CAINFO]); } - if(data->set.str[STRING_SSL_CAPATH]) { - ERROR_CHECK_SETOPT(CURLOPT_CAPATH, data->set.str[STRING_SSL_CAPATH]); + if(CURL_EASY_STR(data, STRING_SSL_CAPATH)) { + ERROR_CHECK_SETOPT(CURLOPT_CAPATH, + CURL_EASY_STR(data, STRING_SSL_CAPATH)); } - if(data->set.str[STRING_SSL_CRLFILE]) { - ERROR_CHECK_SETOPT(CURLOPT_CRLFILE, data->set.str[STRING_SSL_CRLFILE]); + if(CURL_EASY_STR(data, STRING_SSL_CRLFILE)) { + ERROR_CHECK_SETOPT(CURLOPT_CRLFILE, + CURL_EASY_STR(data, STRING_SSL_CRLFILE)); } if(data->set.ssl.certinfo) ERROR_CHECK_SETOPT(CURLOPT_CERTINFO, 1L); @@ -354,9 +357,9 @@ static CURLcode doh_probe_run(struct Curl_easy *data, ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx); if(data->set.ssl.fsslctxp) ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_DATA, data->set.ssl.fsslctxp); - if(data->set.str[STRING_SSL_EC_CURVES]) { + if(CURL_EASY_STR(data, STRING_SSL_EC_CURVES)) { ERROR_CHECK_SETOPT(CURLOPT_SSL_EC_CURVES, - data->set.str[STRING_SSL_EC_CURVES]); + CURL_EASY_STR(data, STRING_SSL_EC_CURVES)); } (void)curl_easy_setopt(doh, CURLOPT_SSL_OPTIONS, @@ -442,7 +445,8 @@ CURLcode Curl_doh(struct Curl_easy *data, if(async->dns_queries & CURL_DNSQ_AAAA) { /* create IPv6 DoH request */ result = doh_probe_run(data, CURL_DNS_TYPE_AAAA, - async->peer->hostname, data->set.str[STRING_DOH], + async->peer->hostname, + CURL_EASY_STR(data, STRING_DOH), data->multi, async->id, &dohp->probe_mid[DOH_SLOT_IPV6]); if(result) @@ -454,7 +458,8 @@ CURLcode Curl_doh(struct Curl_easy *data, /* create IPv4 DoH request */ if(async->dns_queries & CURL_DNSQ_A) { result = doh_probe_run(data, CURL_DNS_TYPE_A, - async->peer->hostname, data->set.str[STRING_DOH], + async->peer->hostname, + CURL_EASY_STR(data, STRING_DOH), data->multi, async->id, &dohp->probe_mid[DOH_SLOT_IPV4]); if(result) @@ -473,7 +478,7 @@ CURLcode Curl_doh(struct Curl_easy *data, } result = doh_probe_run(data, CURL_DNS_TYPE_HTTPS, qname ? qname : async->peer->hostname, - data->set.str[STRING_DOH], data->multi, + CURL_EASY_STR(data, STRING_DOH), data->multi, async->id, &dohp->probe_mid[DOH_SLOT_HTTPS_RR]); curlx_free(qname); diff --git a/lib/vquic/cf-ngtcp2.c b/lib/vquic/cf-ngtcp2.c index f6fd6c55fc..8c7c84928b 100644 --- a/lib/vquic/cf-ngtcp2.c +++ b/lib/vquic/cf-ngtcp2.c @@ -689,9 +689,9 @@ static CURLcode h3_stream_open(struct Curl_cfilter *cf, } result = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, - !data->state.http_ignorecustom ? - data->set.str[STRING_CUSTOMREQUEST] : NULL, - 0, pnwritten); + !data->state.http_ignorecustom ? + CURL_EASY_STR(data, STRING_CUSTOMREQUEST) : NULL, + 0, pnwritten); if(result) goto out; if(!stream->h1.done) { diff --git a/lib/vquic/cf-quiche.c b/lib/vquic/cf-quiche.c index 52dad536b6..c269926dca 100644 --- a/lib/vquic/cf-quiche.c +++ b/lib/vquic/cf-quiche.c @@ -1012,9 +1012,9 @@ static CURLcode h3_open_stream(struct Curl_cfilter *cf, DEBUGASSERT(stream); result = Curl_h1_req_parse_read(&stream->h1, buf, blen, NULL, - !data->state.http_ignorecustom ? - data->set.str[STRING_CUSTOMREQUEST] : NULL, - 0, pnwritten); + !data->state.http_ignorecustom ? + CURL_EASY_STR(data, STRING_CUSTOMREQUEST) : NULL, + 0, pnwritten); if(result) goto out; if(!stream->h1.done) { diff --git a/lib/vquic/vquic-tls.c b/lib/vquic/vquic-tls.c index 58f139306a..75e2f4e1e2 100644 --- a/lib/vquic/vquic-tls.c +++ b/lib/vquic/vquic-tls.c @@ -166,9 +166,9 @@ CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx, (void)conn_config; result = Curl_ossl_check_peer_cert(cf, data, &ctx->ossl, peer); #elif defined(USE_GNUTLS) - result = Curl_gtls_verifyserver(cf, data, ctx->gtls.session, - conn_config, &data->set.ssl, peer, - data->set.str[STRING_SSL_PINNEDPUBLICKEY]); + result = Curl_gtls_verifyserver( + cf, data, ctx->gtls.session, conn_config, &data->set.ssl, peer, + CURL_EASY_STR(data, STRING_SSL_PINNEDPUBLICKEY)); if(result) return result; #elif defined(USE_WOLFSSL) diff --git a/lib/vquic/vquic.c b/lib/vquic/vquic.c index eb13abad73..2603f6b7b1 100644 --- a/lib/vquic/vquic.c +++ b/lib/vquic/vquic.c @@ -1022,7 +1022,7 @@ CURLcode Curl_cf_quic_insert_after(struct Curl_cfilter *cf_at, CURLECH_ENABLED(data) && Curl_ssl_supports(data, SSLSUPP_ECH) && (data->set.tls_ech != CURLECH_GREASE) && - !data->set.str[STRING_ECH_CONFIG]) { + !CURL_EASY_STR(data, STRING_ECH_CONFIG)) { result = Curl_conn_dns_add_https_resolve(data, cf_at->conn, cf_at->sockindex, origin); } diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index e9fe81022d..03a84d218b 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -109,10 +109,10 @@ static CURLcode sftp_error_to_CURLE(int err) } /* Multiple options: - * 1. data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256] is set with a SHA256 - * hash. - * 2. data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] is set with an MD5 - * hash (90s style auth, not sure we should have it here) + * 1. CURL_EASY_STR(data, STRING_SSH_HOST_PUBLIC_KEY_SHA256) is set + * with a SHA256 hash. + * 2. CURL_EASY_STR(data, STRING_SSH_HOST_PUBLIC_KEY_MD5) is set + * with an MD5 hash (90s style auth, not sure we should have it here) * 3. data->set.ssh_keyfunc callback is set. Then we do trust on first * use. We even save on knownhosts if CURLKHSTAT_FINE_ADD_TO_FILE * is returned by it. @@ -143,9 +143,9 @@ static int myssh_is_known(struct Curl_easy *data, struct ssh_conn *sshc) if(rc != SSH_OK) return rc; - if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256]) { + if(CURL_EASY_STR(data, STRING_SSH_HOST_PUBLIC_KEY_SHA256)) { const char *pubkey_sha256 = - data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256]; + CURL_EASY_STR(data, STRING_SSH_HOST_PUBLIC_KEY_SHA256); char *fingerprint_b64 = NULL; size_t fingerprint_b64_len; size_t pub_pos = 0; @@ -197,8 +197,9 @@ static int myssh_is_known(struct Curl_easy *data, struct ssh_conn *sshc) goto cleanup; } - if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) { - const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]; + if(CURL_EASY_STR(data, STRING_SSH_HOST_PUBLIC_KEY_MD5)) { + const char *pubkey_md5 = + CURL_EASY_STR(data, STRING_SSH_HOST_PUBLIC_KEY_MD5); char md5buffer[33]; int i; @@ -227,7 +228,7 @@ static int myssh_is_known(struct Curl_easy *data, struct ssh_conn *sshc) goto cleanup; } - if(data->set.str[STRING_SSH_KNOWNHOSTS]) { + if(CURL_EASY_STR(data, STRING_SSH_KNOWNHOSTS)) { /* Get the known_key from the known hosts file */ vstate = ssh_session_get_known_hosts_entry(sshc->ssh_session, @@ -2618,15 +2619,16 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done) } } - if(data->set.str[STRING_SSH_KNOWNHOSTS]) { - infof(data, "Known hosts: %s", data->set.str[STRING_SSH_KNOWNHOSTS]); + if(CURL_EASY_STR(data, STRING_SSH_KNOWNHOSTS)) { + infof(data, "Known hosts: %s", + CURL_EASY_STR(data, STRING_SSH_KNOWNHOSTS)); rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_KNOWNHOSTS, - data->set.str[STRING_SSH_KNOWNHOSTS]); + CURL_EASY_STR(data, STRING_SSH_KNOWNHOSTS)); if(rc == SSH_OK) /* libssh has two separate options for this. Set both to the same file to avoid surprises */ rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, - data->set.str[STRING_SSH_KNOWNHOSTS]); + CURL_EASY_STR(data, STRING_SSH_KNOWNHOSTS)); if(rc != SSH_OK) { failf(data, "Could not set known hosts file path"); return CURLE_FAILED_INIT; diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index 9d2e8b8e94..098b680f7f 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -316,7 +316,7 @@ static CURLcode ssh_knownhost(struct Curl_easy *data, int rc = 0; CURLcode result = CURLE_OK; - if(!data->set.str[STRING_SSH_KNOWNHOSTS]) { + if(!CURL_EASY_STR(data, STRING_SSH_KNOWNHOSTS)) { infof(data, "SSH: no knownhosts file configured"); return CURLE_OK; } @@ -460,12 +460,12 @@ static CURLcode ssh_knownhost(struct Curl_easy *data, /* now we write the entire in-memory list of known hosts to the known_hosts file */ int wrc = - libssh2_knownhost_writefile(sshc->kh, - data->set.str[STRING_SSH_KNOWNHOSTS], - LIBSSH2_KNOWNHOST_FILE_OPENSSH); + libssh2_knownhost_writefile( + sshc->kh, CURL_EASY_STR(data, STRING_SSH_KNOWNHOSTS), + LIBSSH2_KNOWNHOST_FILE_OPENSSH); if(wrc) { infof(data, "WARNING: writing %s failed", - data->set.str[STRING_SSH_KNOWNHOSTS]); + CURL_EASY_STR(data, STRING_SSH_KNOWNHOSTS)); } } } @@ -481,8 +481,10 @@ static CURLcode ssh_knownhost(struct Curl_easy *data, static CURLcode ssh_check_fingerprint(struct Curl_easy *data, struct ssh_conn *sshc) { - const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]; - const char *pubkey_sha256 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256]; + const char *pubkey_md5 = + CURL_EASY_STR(data, STRING_SSH_HOST_PUBLIC_KEY_MD5); + const char *pubkey_sha256 = + CURL_EASY_STR(data, STRING_SSH_HOST_PUBLIC_KEY_SHA256); if(pubkey_sha256) { const char *fingerprint = NULL; @@ -646,8 +648,8 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data, bool found = FALSE; if(sshc->kh && - !data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] && - !data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256]) { + !CURL_EASY_STR(data, STRING_SSH_HOST_PUBLIC_KEY_MD5) && + !CURL_EASY_STR(data, STRING_SSH_HOST_PUBLIC_KEY_SHA256)) { struct libssh2_knownhost *store = NULL; struct connectdata *conn = data->conn; /* lets try to find our host in the known hosts file */ @@ -663,7 +665,8 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data, const char *kh_name_end = strstr(store->name, "]:"); if(!kh_name_end) { infof(data, "SSH: invalid host pattern %s in %s", - store->name, data->set.str[STRING_SSH_KNOWNHOSTS]); + store->name, + CURL_EASY_STR(data, STRING_SSH_KNOWNHOSTS)); continue; } p = kh_name_end + 2; /* start of port number */ @@ -693,7 +696,8 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data, int rc; const char *hostkey_method = NULL; infof(data, "SSH: found host '%s' in '%s'", - conn->origin->hostname, data->set.str[STRING_SSH_KNOWNHOSTS]); + conn->origin->hostname, + CURL_EASY_STR(data, STRING_SSH_KNOWNHOSTS)); switch(store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) { case LIBSSH2_KNOWNHOST_KEY_ED25519: @@ -738,7 +742,8 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data, } else { infof(data, "SSH: did not find host '%s' in '%s'", - conn->origin->hostname, data->set.str[STRING_SSH_KNOWNHOSTS]); + conn->origin->hostname, + CURL_EASY_STR(data, STRING_SSH_KNOWNHOSTS)); } } @@ -3475,7 +3480,7 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done) infof(data, "SSH: failed to enable compression for session"); } - if(data->set.str[STRING_SSH_KNOWNHOSTS]) { + if(CURL_EASY_STR(data, STRING_SSH_KNOWNHOSTS)) { int rc; sshc->kh = libssh2_knownhost_init(sshc->ssh_session); if(!sshc->kh) { @@ -3485,12 +3490,12 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done) } /* read all known hosts from there */ - rc = libssh2_knownhost_readfile(sshc->kh, - data->set.str[STRING_SSH_KNOWNHOSTS], - LIBSSH2_KNOWNHOST_FILE_OPENSSH); + rc = libssh2_knownhost_readfile( + sshc->kh, CURL_EASY_STR(data, STRING_SSH_KNOWNHOSTS), + LIBSSH2_KNOWNHOST_FILE_OPENSSH); if(rc < 0) infof(data, "SSH: failed to read known hosts from %s", - data->set.str[STRING_SSH_KNOWNHOSTS]); + CURL_EASY_STR(data, STRING_SSH_KNOWNHOSTS)); } #ifdef CURL_LIBSSH2_DEBUG diff --git a/lib/vssh/vssh.c b/lib/vssh/vssh.c index ac02171829..f8e687382c 100644 --- a/lib/vssh/vssh.c +++ b/lib/vssh/vssh.c @@ -368,8 +368,9 @@ CURLcode Curl_ssh_setup_pkey(struct Curl_easy *data, struct ssh_conn *sshc) if(data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) { sshc->pub_key = sshc->priv_key = NULL; - if(data->set.str[STRING_SSH_PRIVATE_KEY]) { - sshc->priv_key = curlx_strdup(data->set.str[STRING_SSH_PRIVATE_KEY]); + if(CURL_EASY_STR(data, STRING_SSH_PRIVATE_KEY)) { + sshc->priv_key = curlx_strdup( + CURL_EASY_STR(data, STRING_SSH_PRIVATE_KEY)); if(!sshc->priv_key) goto fail; } @@ -417,10 +418,11 @@ CURLcode Curl_ssh_setup_pkey(struct Curl_easy *data, struct ssh_conn *sshc) * library extract the public key from the private key file. This is done * by passing sshc->pub_key = NULL. */ - if(data->set.str[STRING_SSH_PUBLIC_KEY] && + if(CURL_EASY_STR(data, STRING_SSH_PUBLIC_KEY) && /* treat empty string the same way as NULL */ - data->set.str[STRING_SSH_PUBLIC_KEY][0]) { - sshc->pub_key = curlx_strdup(data->set.str[STRING_SSH_PUBLIC_KEY]); + CURL_EASY_STR(data, STRING_SSH_PUBLIC_KEY)[0]) { + sshc->pub_key = curlx_strdup( + CURL_EASY_STR(data, STRING_SSH_PUBLIC_KEY)); if(!sshc->pub_key) goto fail; } diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index b49148982b..ba9da769df 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -1868,10 +1868,10 @@ static CURLcode gtls_verifyserver(struct Curl_cfilter *cf, struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); #ifndef CURL_DISABLE_PROXY const char *pinned_key = Curl_ssl_cf_is_proxy(cf) ? - data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : - data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + CURL_EASY_STR(data, STRING_SSL_PINNEDPUBLICKEY_PROXY) : + CURL_EASY_STR(data, STRING_SSL_PINNEDPUBLICKEY); #else - const char *pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + const char *pinned_key = CURL_EASY_STR(data, STRING_SSL_PINNEDPUBLICKEY); #endif CURLcode result; diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index 664d1f97a2..d10c4b27f9 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -1075,10 +1075,11 @@ static CURLcode mbed_connect_step2(struct Curl_cfilter *cf, #ifdef HAVE_PINNED_PUBKEY #ifndef CURL_DISABLE_PROXY const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf) ? - data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : - data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + CURL_EASY_STR(data, STRING_SSL_PINNEDPUBLICKEY_PROXY) : + CURL_EASY_STR(data, STRING_SSL_PINNEDPUBLICKEY); #else - const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + const char * const pinnedpubkey = + CURL_EASY_STR(data, STRING_SSL_PINNEDPUBLICKEY); #endif #endif diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 802f3da862..4505cc31eb 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -3477,7 +3477,7 @@ bool Curl_ossl_need_httpsrr(struct Curl_easy *data) if(!CURLECH_ENABLED(data)) return FALSE; if((data->set.tls_ech == CURLECH_GREASE) || - data->set.str[STRING_ECH_CONFIG]) + CURL_EASY_STR(data, STRING_ECH_CONFIG)) return FALSE; return TRUE; } @@ -3487,9 +3487,7 @@ static CURLcode ossl_init_ech(struct ossl_ctx *octx, struct Curl_easy *data, struct ssl_peer *peer) { - unsigned char *ech_config = NULL; - size_t ech_config_len = 0; - char *outername = data->set.str[STRING_ECH_PUBLIC]; + const char *outername = CURL_EASY_STR(data, STRING_ECH_PUBLIC); int trying_ech_now = 0; if(!CURLECH_ENABLED(data)) @@ -3503,10 +3501,12 @@ static CURLcode ossl_init_ech(struct ossl_ctx *octx, SSL_set_options(octx->ssl, SSL_OP_ECH_GREASE); #endif } - else if(data->set.tls_ech && data->set.str[STRING_ECH_CONFIG]) { + else if(data->set.tls_ech && CURL_EASY_STR(data, STRING_ECH_CONFIG)) { #ifdef HAVE_BORINGSSL_LIKE /* have to do base64 decode here for BoringSSL */ - const char *b64 = data->set.str[STRING_ECH_CONFIG]; + const char *b64 = CURL_EASY_STR(data, STRING_ECH_CONFIG); + uint8_t *ech_config; + size_t ech_config_len = 0; CURLcode result; if(!b64) { @@ -3530,13 +3530,16 @@ static CURLcode ossl_init_ech(struct ossl_ctx *octx, curlx_free(ech_config); trying_ech_now = 1; #else - ech_config = (unsigned char *)data->set.str[STRING_ECH_CONFIG]; + const char *ech_config = CURL_EASY_STR(data, STRING_ECH_CONFIG); + size_t ech_config_len = 0; if(!ech_config) { infof(data, "ECH: ECHConfig from command line empty"); return CURLE_SSL_CONNECT_ERROR; } - ech_config_len = strlen(data->set.str[STRING_ECH_CONFIG]); - if(SSL_set1_ech_config_list(octx->ssl, ech_config, ech_config_len) != 1) { + ech_config_len = strlen(ech_config); + if(SSL_set1_ech_config_list(octx->ssl, + (const uint8_t *)ech_config, + ech_config_len) != 1) { infof(data, "ECH: SSL_ECH_set1_ech_config_list failed"); if(data->set.tls_ech == CURLECH_HARD) return CURLE_SSL_CONNECT_ERROR; @@ -4599,10 +4602,10 @@ static CURLcode ossl_check_pinned_key(struct Curl_cfilter *cf, (void)cf; #ifndef CURL_DISABLE_PROXY ptr = Curl_ssl_cf_is_proxy(cf) ? - data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : - data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + CURL_EASY_STR(data, STRING_SSL_PINNEDPUBLICKEY_PROXY) : + CURL_EASY_STR(data, STRING_SSL_PINNEDPUBLICKEY); #else - ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + ptr = CURL_EASY_STR(data, STRING_SSL_PINNEDPUBLICKEY); #endif if(ptr) { result = ossl_pkp_pin_peer_pubkey(data, server_cert, ptr); diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index ef2ace2646..31e7a5f351 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -923,7 +923,7 @@ static bool cr_ech_need_httpsrr(struct Curl_easy *data) if(!CURLECH_ENABLED(data)) return FALSE; if((data->set.tls_ech == CURLECH_GREASE) || - data->set.str[STRING_ECH_CONFIG]) + CURL_EASY_STR(data, STRING_ECH_CONFIG)) return FALSE; return TRUE; } @@ -948,7 +948,7 @@ init_config_builder_ech(struct Curl_easy *data, goto cleanup; } - if(data->set.str[STRING_ECH_PUBLIC]) { + if(CURL_EASY_STR(data, STRING_ECH_PUBLIC)) { failf(data, "rustls: ECH outername not supported"); result = CURLE_SSL_CONNECT_ERROR; goto cleanup; @@ -964,8 +964,8 @@ init_config_builder_ech(struct Curl_easy *data, return CURLE_OK; } - if(data->set.tls_ech && data->set.str[STRING_ECH_CONFIG]) { - const char *b64 = data->set.str[STRING_ECH_CONFIG]; + if(data->set.tls_ech && CURL_EASY_STR(data, STRING_ECH_CONFIG)) { + const char *b64 = CURL_EASY_STR(data, STRING_ECH_CONFIG); size_t decode_result; if(!b64) { infof(data, "rustls: ECHConfig from command line empty"); @@ -1005,7 +1005,7 @@ init_config_builder_ech(struct Curl_easy *data, } cleanup: /* if we base64 decoded, we can free now */ - if(data->set.tls_ech && data->set.str[STRING_ECH_CONFIG]) { + if(data->set.tls_ech && CURL_EASY_STR(data, STRING_ECH_CONFIG)) { curlx_free(ech_config); } if(dns) { diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index eea5f3af55..cee933b3aa 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -1458,10 +1458,10 @@ static CURLcode schannel_connect_step2(struct Curl_cfilter *cf, #ifndef CURL_DISABLE_PROXY pubkey_ptr = Curl_ssl_cf_is_proxy(cf) ? - data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : - data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + CURL_EASY_STR(data, STRING_SSL_PINNEDPUBLICKEY_PROXY) : + CURL_EASY_STR(data, STRING_SSL_PINNEDPUBLICKEY); #else - pubkey_ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + pubkey_ptr = CURL_EASY_STR(data, STRING_SSL_PINNEDPUBLICKEY); #endif if(pubkey_ptr) { result = schannel_pkp_pin_peer_pubkey(cf, data, pubkey_ptr); diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index c1504fad3b..f6cc370890 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -1431,7 +1431,7 @@ CURLcode Curl_cf_ssl_insert_after(struct Curl_cfilter *cf_at, CURLECH_ENABLED(data) && Curl_ssl_supports(data, SSLSUPP_ECH) && (data->set.tls_ech != CURLECH_GREASE) && - !data->set.str[STRING_ECH_CONFIG]) { + !CURL_EASY_STR(data, STRING_ECH_CONFIG)) { result = Curl_conn_dns_add_https_resolve(data, cf->conn, cf->sockindex, origin); } diff --git a/lib/vtls/vtls_config.c b/lib/vtls/vtls_config.c index 252c5ad885..afd66d475f 100644 --- a/lib/vtls/vtls_config.c +++ b/lib/vtls/vtls_config.c @@ -236,12 +236,18 @@ static void ssl_easy_config_compl_options(struct Curl_peer *origin, !!(options & CURLSSLOPT_AUTO_CLIENT_CERT); } +static char *ssl_easy_steal(struct Curl_easy *data, enum dupstring id) +{ + /* For connection matching, we borrow string references from data + * THIS IS NOT REALLY NICE. */ + return CURL_UNCONST(CURL_EASY_STR(data, id)); +} + CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data, struct Curl_peer *origin) { struct ssl_config_data *sslc = &data->set.ssl; #if defined(CURL_CA_PATH) || defined(CURL_CA_BUNDLE) - struct UserDefined *set = &data->set; CURLcode result; #endif @@ -253,42 +259,43 @@ CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data, sslc->native_ca_store = TRUE; #endif #ifdef CURL_CA_PATH - if(!sslc->custom_capath && !set->str[STRING_SSL_CAPATH]) { - result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH); + if(!sslc->custom_capath && !CURL_EASY_STR(data, STRING_SSL_CAPATH)) { + result = Curl_setstropt(data, STRING_SSL_CAPATH, CURL_CA_PATH); if(result) return result; } #endif #ifdef CURL_CA_BUNDLE - if(!sslc->custom_cafile && !set->str[STRING_SSL_CAFILE]) { - result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE); + if(!sslc->custom_cafile && !CURL_EASY_STR(data, STRING_SSL_CAFILE)) { + result = Curl_setstropt(data, STRING_SSL_CAFILE, CURL_CA_BUNDLE); if(result) return result; } #endif } - sslc->primary.CAfile = data->set.str[STRING_SSL_CAFILE]; - sslc->primary.CRLfile = data->set.str[STRING_SSL_CRLFILE]; - sslc->primary.CApath = data->set.str[STRING_SSL_CAPATH]; - sslc->primary.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST]; - sslc->primary.cipher_list13 = data->set.str[STRING_SSL_CIPHER13_LIST]; + sslc->primary.CAfile = ssl_easy_steal(data, STRING_SSL_CAFILE); + sslc->primary.CRLfile = ssl_easy_steal(data, STRING_SSL_CRLFILE); + sslc->primary.CApath = ssl_easy_steal(data, STRING_SSL_CAPATH); + sslc->primary.cipher_list = ssl_easy_steal(data, STRING_SSL_CIPHER_LIST); + sslc->primary.cipher_list13 = ssl_easy_steal(data, STRING_SSL_CIPHER13_LIST); sslc->primary.signature_algorithms = - data->set.str[STRING_SSL_SIGNATURE_ALGORITHMS]; + ssl_easy_steal(data, STRING_SSL_SIGNATURE_ALGORITHMS); sslc->primary.ca_info_blob = data->set.blobs[BLOB_CAINFO]; - sslc->primary.curves = data->set.str[STRING_SSL_EC_CURVES]; + sslc->primary.curves = ssl_easy_steal(data, STRING_SSL_EC_CURVES); /* Maybe these should not be used for another origin. But for * backwards compatibility, keep them in. */ - sslc->primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT]; + sslc->primary.issuercert = ssl_easy_steal(data, STRING_SSL_ISSUERCERT); sslc->primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT]; if(Curl_peer_equal(data->state.initial_origin, origin)) { - sslc->primary.pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + sslc->primary.pinned_key = + ssl_easy_steal(data, STRING_SSL_PINNEDPUBLICKEY); sslc->primary.cert_blob = data->set.blobs[BLOB_CERT]; - sslc->primary.cert_type = data->set.str[STRING_CERT_TYPE]; - sslc->primary.key = data->set.str[STRING_KEY]; - sslc->primary.key_type = data->set.str[STRING_KEY_TYPE]; - sslc->primary.key_passwd = data->set.str[STRING_KEY_PASSWD]; - sslc->primary.clientcert = data->set.str[STRING_CERT]; + sslc->primary.cert_type = ssl_easy_steal(data, STRING_CERT_TYPE); + sslc->primary.key = ssl_easy_steal(data, STRING_KEY); + sslc->primary.key_type = ssl_easy_steal(data, STRING_KEY_TYPE); + sslc->primary.key_passwd = ssl_easy_steal(data, STRING_KEY_PASSWD); + sslc->primary.clientcert = ssl_easy_steal(data, STRING_CERT); sslc->primary.key_blob = data->set.blobs[BLOB_KEY]; } else { @@ -313,37 +320,40 @@ CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data, sslc->native_ca_store = TRUE; #endif #ifdef CURL_CA_PATH - if(!sslc->custom_capath && !set->str[STRING_SSL_CAPATH_PROXY]) { - result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], - CURL_CA_PATH); + if(!sslc->custom_capath && + !CURL_EASY_STR(data, STRING_SSL_CAPATH_PROXY)) { + result = Curl_setstropt(data, STRING_SSL_CAPATH_PROXY, CURL_CA_PATH); if(result) return result; } #endif #ifdef CURL_CA_BUNDLE - if(!sslc->custom_cafile && !set->str[STRING_SSL_CAFILE_PROXY]) { - result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY], - CURL_CA_BUNDLE); + if(!sslc->custom_cafile && + !CURL_EASY_STR(data, STRING_SSL_CAFILE_PROXY)) { + result = Curl_setstropt(data, STRING_SSL_CAFILE_PROXY, CURL_CA_BUNDLE); if(result) return result; } #endif } - sslc->primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY]; - sslc->primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY]; - sslc->primary.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST_PROXY]; - sslc->primary.cipher_list13 = data->set.str[STRING_SSL_CIPHER13_LIST_PROXY]; - sslc->primary.pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]; + sslc->primary.CAfile = ssl_easy_steal(data, STRING_SSL_CAFILE_PROXY); + sslc->primary.CApath = ssl_easy_steal(data, STRING_SSL_CAPATH_PROXY); + sslc->primary.cipher_list = + ssl_easy_steal(data, STRING_SSL_CIPHER_LIST_PROXY); + sslc->primary.cipher_list13 = + ssl_easy_steal(data, STRING_SSL_CIPHER13_LIST_PROXY); + sslc->primary.pinned_key = + ssl_easy_steal(data, STRING_SSL_PINNEDPUBLICKEY_PROXY); sslc->primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY]; sslc->primary.ca_info_blob = data->set.blobs[BLOB_CAINFO_PROXY]; - sslc->primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY]; + sslc->primary.issuercert = ssl_easy_steal(data, STRING_SSL_ISSUERCERT_PROXY); sslc->primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY]; - sslc->primary.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY]; - sslc->primary.cert_type = data->set.str[STRING_CERT_TYPE_PROXY]; - sslc->primary.key = data->set.str[STRING_KEY_PROXY]; - sslc->primary.key_type = data->set.str[STRING_KEY_TYPE_PROXY]; - sslc->primary.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY]; - sslc->primary.clientcert = data->set.str[STRING_CERT_PROXY]; + sslc->primary.CRLfile = ssl_easy_steal(data, STRING_SSL_CRLFILE_PROXY); + sslc->primary.cert_type = ssl_easy_steal(data, STRING_CERT_TYPE_PROXY); + sslc->primary.key = ssl_easy_steal(data, STRING_KEY_PROXY); + sslc->primary.key_type = ssl_easy_steal(data, STRING_KEY_TYPE_PROXY); + sslc->primary.key_passwd = ssl_easy_steal(data, STRING_KEY_PASSWD_PROXY); + sslc->primary.clientcert = ssl_easy_steal(data, STRING_CERT_PROXY); sslc->primary.key_blob = data->set.blobs[BLOB_KEY_PROXY]; #endif /* CURL_DISABLE_PROXY */ diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index 05d89ea1ea..b8a07fb6fd 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -1260,7 +1260,7 @@ static CURLcode wssl_init_ech(struct wssl_ctx *wctx, { int trying_ech_now = 0; - if(data->set.str[STRING_ECH_PUBLIC]) { + if(CURL_EASY_STR(data, STRING_ECH_PUBLIC)) { infof(data, "ECH: outername not (yet) supported" " with wolfSSL"); return CURLE_SSL_CONNECT_ERROR; @@ -1269,8 +1269,8 @@ static CURLcode wssl_init_ech(struct wssl_ctx *wctx, infof(data, "ECH: GREASE is done by default by" " wolfSSL: no need to ask"); } - if(data->set.tls_ech && data->set.str[STRING_ECH_CONFIG]) { - char *b64val = data->set.str[STRING_ECH_CONFIG]; + if(data->set.tls_ech && CURL_EASY_STR(data, STRING_ECH_CONFIG)) { + const char *b64val = CURL_EASY_STR(data, STRING_ECH_CONFIG); word32 b64len = 0; b64len = (word32)strlen(b64val); @@ -1477,7 +1477,7 @@ bool Curl_wssl_need_httpsrr(struct Curl_easy *data) if(!CURLECH_ENABLED(data)) return FALSE; if((data->set.tls_ech == CURLECH_GREASE) || - data->set.str[STRING_ECH_CONFIG]) + CURL_EASY_STR(data, STRING_ECH_CONFIG)) return FALSE; return TRUE; #else @@ -1580,10 +1580,11 @@ CURLcode Curl_wssl_verify_pinned(struct Curl_cfilter *cf, CURLcode result = CURLE_OK; #ifndef CURL_DISABLE_PROXY const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf) ? - data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : - data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + CURL_EASY_STR(data, STRING_SSL_PINNEDPUBLICKEY_PROXY) : + CURL_EASY_STR(data, STRING_SSL_PINNEDPUBLICKEY); #else - const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + const char * const pinnedpubkey = + CURL_EASY_STR(data, STRING_SSL_PINNEDPUBLICKEY); (void)cf; #endif diff --git a/projects/OS400/ccsidcurl.c b/projects/OS400/ccsidcurl.c index d6ad035b29..1cce770a3f 100644 --- a/projects/OS400/ccsidcurl.c +++ b/projects/OS400/ccsidcurl.c @@ -1205,7 +1205,7 @@ CURLcode curl_easy_setopt_ccsid(CURL *curl, CURLoption tag, ...) } result = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, s); - data->set.str[STRING_COPYPOSTFIELDS] = s; /* Give to library. */ + data->set.str_copypostfields = s; /* Give to library. */ break; default: diff --git a/tests/data/test3211 b/tests/data/test3211 index 826c961a4d..1c2643abc1 100644 --- a/tests/data/test3211 +++ b/tests/data/test3211 @@ -13,7 +13,7 @@ uint_bset unittest -uint_bset unit tests +uint_bset and uint_hashset unit tests diff --git a/tests/unit/unit1620.c b/tests/unit/unit1620.c index a58a586afe..3fd4f4b0a4 100644 --- a/tests/unit/unit1620.c +++ b/tests/unit/unit1620.c @@ -127,7 +127,7 @@ static CURLcode test_unit1620(const char *arg) Curl_freeset(empty); for(i = (enum dupstring)0; i < STRING_LAST; i++) { - fail_unless(!empty->set.str[i], "Curl_free() did not set to NULL"); + fail_unless(!CURL_EASY_STR(empty, i), "Curl_free() did not set to NULL"); } result = Curl_close(&dupe); diff --git a/tests/unit/unit3211.c b/tests/unit/unit3211.c index 0d1dde200d..516f516af6 100644 --- a/tests/unit/unit3211.c +++ b/tests/unit/unit3211.c @@ -24,10 +24,11 @@ #include "unitcheck.h" #include "urldata.h" #include "uint-bset.h" +#include "uint-hashset.h" #include "curl_trc.h" -static void check_set(const char *name, uint32_t capacity, - const uint32_t *s, size_t slen) +static void t3211_check_bset(const char *name, uint32_t capacity, + const uint32_t *s, size_t slen) { struct uint32_bset bset; size_t i, j; @@ -122,6 +123,103 @@ static void check_set(const char *name, uint32_t capacity, Curl_uint32_bset_destroy(&bset); } +static bool t3211_strcmp(const char *s1, const char *s2) +{ + if(s1 && s2) + return strcmp(s1, s2); + return s1 == s2; +} + +static void t3211_check_strset1(void) +{ + struct u8_strset set; + char buf[128]; + CURLcode result; + uint8_t i, idx; + int j; + + Curl_u8_strset_init(&set); + fail_unless(!Curl_u8_strset_count(&set), "initial strset not empty"); + + result = Curl_u8_strset_set(&set, 0, "123"); + fail_unless(!result, "add1 failed"); + fail_unless(Curl_u8_strset_get(&set, 0), "get failed"); + fail_unless(!t3211_strcmp("123", Curl_u8_strset_get(&set, 0)), "wrong get1"); + result = Curl_u8_strset_set(&set, 0, "456"); + fail_unless(!result, "add2 failed"); + fail_unless(!t3211_strcmp("456", Curl_u8_strset_get(&set, 0)), "wrong get2"); + Curl_u8_strset_unset(&set, 0); + fail_unless(!Curl_u8_strset_get(&set, 0), "unset failed"); + + /* Initial size is 4, add 4 hash collisions */ + for(i = 0; i < 4; ++i) { + idx = (uint8_t)((4 * i) + 3); + curl_msnprintf(buf, sizeof(buf), "str-%d", idx); + result = Curl_u8_strset_set(&set, idx, buf); + fail_unless(!result, "loop4-add failed"); + fail_unless(!t3211_strcmp(buf, Curl_u8_strset_get(&set, idx)), + "wrong get loop4"); + } + + /* Remove collided entry 2, check again */ + idx = (uint8_t)((4 * 2) + 3); + Curl_u8_strset_unset(&set, idx); + fail_unless(!Curl_u8_strset_get(&set, idx), "unset2 failed"); + for(i = 0; i < 4; ++i) { + if(i == 2) + continue; + idx = (uint8_t)((4 * i) + 3); + curl_msnprintf(buf, sizeof(buf), "str-%d", idx); + fail_unless(!t3211_strcmp(buf, Curl_u8_strset_get(&set, idx)), + "wrong get loop6"); + } + + /* Add entry 2 again, check */ + idx = (uint8_t)((4 * 2) + 3); + curl_msnprintf(buf, sizeof(buf), "str-%d", idx); + result = Curl_u8_strset_set(&set, idx, buf); + fail_unless(!result, "re-add 2 failed"); + fail_unless(!t3211_strcmp(buf, Curl_u8_strset_get(&set, idx)), + "wrong re-add 2 get"); + for(i = 0; i < 4; ++i) { + idx = (uint8_t)((4 * i) + 3); + curl_msnprintf(buf, sizeof(buf), "str-%d", idx); + fail_unless(!t3211_strcmp(buf, Curl_u8_strset_get(&set, idx)), + "wrong get loop6"); + } + + /* Add a 5th, set grows */ + fail_unless(Curl_u8_strset_count(&set) == 4, "wrong count pre add 5"); + idx = (uint8_t)((4 * 4) + 3); + curl_msnprintf(buf, sizeof(buf), "str-%d", idx); + result = Curl_u8_strset_set(&set, idx, buf); + fail_unless(!result, "add4 failed"); + fail_unless(!t3211_strcmp(buf, Curl_u8_strset_get(&set, idx)), + "wrong get4"); + for(i = 0; i < 5; ++i) { + idx = (uint8_t)((4 * i) + 3); + curl_msnprintf(buf, sizeof(buf), "str-%d", idx); + fail_unless(!t3211_strcmp(buf, Curl_u8_strset_get(&set, idx)), + "wrong get loop5"); + } + fail_unless(Curl_u8_strset_count(&set) == 5, "wrong count aftger add 5"); + + Curl_u8_strset_clear(&set); + + /* Make a full set */ + for(j = 0; j <= UINT8_MAX; ++j) { + i = (uint8_t)j; + curl_msnprintf(buf, sizeof(buf), "str-%d", i); + result = Curl_u8_strset_set(&set, i, buf); + fail_unless(!result, "loop256-add failed"); + fail_unless(!t3211_strcmp(buf, Curl_u8_strset_get(&set, i)), + "wrong get loop256"); + } + + Curl_u8_strset_clear(&set); + fail_unless(!Curl_u8_strset_count(&set), "cleared strset not empty"); +} + static CURLcode test_unit3211(const char *arg) { UNITTEST_BEGIN_SIMPLE @@ -142,8 +240,10 @@ static CURLcode test_unit3211(const char *arg) 120, 121, 122, 123, 124, 125, 126, 127, }; - check_set("s1", 100, s1, CURL_ARRAYSIZE(s1)); - check_set("s2", 1000, s2, CURL_ARRAYSIZE(s2)); + t3211_check_bset("s1", 100, s1, CURL_ARRAYSIZE(s1)); + t3211_check_bset("s2", 1000, s2, CURL_ARRAYSIZE(s2)); + + t3211_check_strset1(); UNITTEST_END_SIMPLE }