From fe703df949864cbae594d102d43c4b9ad3e30ef0 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 14 Aug 2026 14:35:04 +0200 Subject: [PATCH] lib: optimize struct layouts for reduced memory usage struct SingleRequest tweaks - 'upgr101' from enum upgrade101 => 'unsigned char', saves three bytes - made some 'unsigned char' => uint8_t - moved 'io_flags' to fill a hole on 64-bit arch struct UserDefined tweaks - Sort the fields by size. Larger to smaller. Helps avoding holes. - httpsig_algorithm moved - FTP uint8_t fields moved - new_file_perms moved - rtspreq moved - sort fields on size - urldata: drop 'struct Curl_data_priority' It only had a single struct member 'weight'. Use that directly instead to save indirections and struct alignments. Move field for size order. - urldata: move the RTSP fields in the UrlState struct to be ordered by size struct PureInfo tweaks - make 'pxcode' a uint8_t - move 'conn_protocol' to fill a hole - sort 'struct PureInfo' fields by size Closes #22585 --- lib/http2.c | 17 ++++---- lib/request.h | 8 ++-- lib/setopt.c | 2 +- lib/socks.c | 2 +- lib/url.c | 4 +- lib/urldata.h | 108 ++++++++++++++++++++++++-------------------------- 6 files changed, 67 insertions(+), 74 deletions(-) diff --git a/lib/http2.c b/lib/http2.c index 03f226c92e..b4787f156f 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -704,7 +704,7 @@ static struct Curl_easy *h2_duphandle(struct Curl_cfilter *cf, if(second) { struct h2_stream_ctx *second_stream; http2_data_setup(cf, second, &second_stream); - second->state.priority.weight = data->state.priority.weight; + second->state.weight = data->state.weight; if(data->share) (void)Curl_share_easy_link(second, data->share); } @@ -1757,15 +1757,15 @@ out: static int sweight_wanted(const struct Curl_easy *data) { /* 0 weight is not set by user and we take the nghttp2 default one */ - return data->set.priority.weight ? - data->set.priority.weight : NGHTTP2_DEFAULT_WEIGHT; + return data->set.weight ? + data->set.weight : NGHTTP2_DEFAULT_WEIGHT; } static int sweight_in_effect(const struct Curl_easy *data) { /* 0 weight is not set by user and we take the nghttp2 default one */ - return data->state.priority.weight ? - data->state.priority.weight : NGHTTP2_DEFAULT_WEIGHT; + return data->state.weight ? + data->state.weight : NGHTTP2_DEFAULT_WEIGHT; } /* @@ -1777,10 +1777,9 @@ static int sweight_in_effect(const struct Curl_easy *data) static void h2_pri_spec(struct Curl_easy *data, nghttp2_priority_spec *pri_spec) { - struct Curl_data_priority *prio = &data->set.priority; - nghttp2_priority_spec_init(pri_spec, 0, - sweight_wanted(data), FALSE); - data->state.priority = *prio; + int prio = data->set.weight; + nghttp2_priority_spec_init(pri_spec, 0, sweight_wanted(data), FALSE); + data->state.weight = prio; } /* diff --git a/lib/request.h b/lib/request.h index ec127cb82e..a7c0a93dd3 100644 --- a/lib/request.h +++ b/lib/request.h @@ -95,9 +95,10 @@ struct SingleRequest { first one */ int httpcode; /* error code from the 'HTTP/1.? XXX' or 'RTSP/1.? XXX' line */ - unsigned char httpversion_sent; /* Version in request (09, 10, 11, etc.) */ - unsigned char httpversion; /* Version in response (09, 10, 11, etc.) */ - enum upgrade101 upgr101; /* 101 upgrade state */ + uint8_t httpversion_sent; /* Version in request (09, 10, 11, etc.) */ + uint8_t httpversion; /* Version in response (09, 10, 11, etc.) */ + uint8_t upgr101; /* 101 upgrade state */ + uint8_t io_flags; /* REQ_IO_RECV | REQ_IO_SEND */ /* Client Writer stack, handles transfer- and content-encodings, protocol * checks, pausing by client callbacks. */ @@ -117,7 +118,6 @@ struct SingleRequest { header data */ char *newurl; /* Set to the new URL to use when a redirect or a retry is wanted */ - uint8_t io_flags; /* REQ_IO_RECV | REQ_IO_SEND */ char *hd_auth; /* Authorization header, full HTTP/1.x line */ #ifndef CURL_DISABLE_PROXY diff --git a/lib/setopt.c b/lib/setopt.c index 924263478b..d6c641f780 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -1062,7 +1062,7 @@ static CURLcode setopt_long_http(struct Curl_easy *data, CURLoption option, case CURLOPT_STREAM_WEIGHT: #if defined(USE_HTTP2) || defined(USE_HTTP3) if((arg >= 1) && (arg <= 256)) - s->priority.weight = (int)arg; + s->weight = (int)arg; break; #else result = CURLE_NOT_BUILT_IN; diff --git a/lib/socks.c b/lib/socks.c index 4f98912a54..949f20c135 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -1196,7 +1196,7 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf, if(pxresult) { result = CURLE_PROXY; - data->info.pxcode = pxresult; + data->info.pxcode = (uint8_t)pxresult; goto out; } else if(ctx->state != SOCKS_ST_SUCCESS) diff --git a/lib/url.c b/lib/url.c index f2f74d8b2e..60421f688d 100644 --- a/lib/url.c +++ b/lib/url.c @@ -429,7 +429,7 @@ void Curl_init_userdefined(struct Curl_easy *data) set->http09_allowed = FALSE; set->httpwant = CURL_HTTP_VERSION_NONE; #if defined(USE_HTTP2) || defined(USE_HTTP3) - memset(&set->priority, 0, sizeof(set->priority)); + set->weight = 0; #endif set->quick_exit = 0L; #ifndef CURL_DISABLE_WEBSOCKETS @@ -2570,7 +2570,7 @@ CURLcode Curl_init_transfer(struct Curl_easy *data, struct connectdata *conn) void Curl_data_priority_clear_state(struct Curl_easy *data) { - memset(&data->state.priority, 0, sizeof(data->state.priority)); + data->state.weight = 0; } #endif /* USE_HTTP2 || USE_HTTP3 */ diff --git a/lib/urldata.h b/lib/urldata.h index 9aebefafcd..95ff12a8b2 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -396,22 +396,6 @@ struct connectdata { * All variables in this struct must be initialized/reset in Curl_initinfo(). */ struct PureInfo { - int httpcode; /* Recent HTTP, FTP, RTSP or SMTP response code */ - int httpproxycode; /* response code from proxy when received separate */ - int httpversion; /* the http version number X.Y = X*10+Y */ - time_t filetime; /* If requested, this is might get set. Set to -1 if the - time was unretrievable. */ - curl_off_t request_size; /* the amount of bytes sent in the request(s) */ - curl_off_t numconnects; /* how many new connections libcurl created */ - uint32_t proxyauthavail; /* what proxy auth types were announced */ - uint32_t httpauthavail; /* what host auth types were announced */ - uint32_t proxyauthpicked; /* selected proxy auth type */ - uint32_t httpauthpicked; /* selected host auth type */ - char *contenttype; /* the content type of the object */ - char *wouldredirect; /* URL this would have been redirected to if asked to */ - curl_off_t retry_after; /* info from Retry-After: header */ - uint32_t header_size; /* size of read header(s) in bytes */ - /* PureInfo primary ip_quadruple is copied over from the connectdata struct in order to allow curl_easy_getinfo() to return this information even when the session handle is no longer associated with a connection, @@ -419,11 +403,26 @@ struct PureInfo { session handle without disturbing information which is still alive, and that might be reused, in the connection pool. */ struct ip_quadruple primary; - const char *conn_scheme; - uint32_t conn_protocol; struct curl_certinfo certs; /* info about the certs. Asked for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ - CURLproxycode pxcode; + time_t filetime; /* If requested, this is might get set. Set to -1 if the + time was unretrievable. */ + curl_off_t request_size; /* the amount of bytes sent in the request(s) */ + curl_off_t numconnects; /* how many new connections libcurl created */ + char *contenttype; /* the content type of the object */ + char *wouldredirect; /* URL this would have been redirected to if asked to */ + curl_off_t retry_after; /* info from Retry-After: header */ + const char *conn_scheme; + int httpcode; /* Recent HTTP, FTP, RTSP or SMTP response code */ + int httpproxycode; /* response code from proxy when received separate */ + int httpversion; /* the http version number X.Y = X*10+Y */ + uint32_t conn_protocol; + uint32_t proxyauthavail; /* what proxy auth types were announced */ + uint32_t httpauthavail; /* what host auth types were announced */ + uint32_t proxyauthpicked; /* selected proxy auth type */ + uint32_t httpauthpicked; /* selected host auth type */ + uint32_t header_size; /* size of read header(s) in bytes */ + uint8_t pxcode; /* holds a CURLproxycode */ BIT(timecond); /* set to TRUE if the time condition did not match, which thus made the document NOT get fetched */ BIT(used_proxy); /* the transfer used a proxy */ @@ -496,14 +495,6 @@ struct Curl_data_prio_node { }; #endif -/** - * Priority information for an easy handle in relation to others - * on the same connection. - */ -struct Curl_data_priority { - int weight; -}; - /* Timers */ typedef enum { EXPIRE_100_TIMEOUT, @@ -583,8 +574,6 @@ struct UrlState { void *baseprov; void *libctx; char *propq; /* for a provider */ - - BIT(provider_loaded); #endif /* USE_OPENSSL */ struct expire_timers timeouts; /* expire timeouts */ @@ -593,22 +582,8 @@ struct UrlState { char *range; /* range, if used. See README for detailed specification on this syntax. */ curl_off_t resume_from; /* continue [ftp] transfer from here */ - -#ifndef CURL_DISABLE_RTSP - /* This RTSP state information survives requests and connections */ - uint32_t rtsp_next_client_CSeq; /* the session's next client CSeq */ - uint32_t rtsp_next_server_CSeq; /* the session's next server CSeq */ - uint32_t rtsp_CSeq_recv; /* most recent CSeq received */ - uint8_t rtp_channel_mask[32]; /* for the correctness checking of the - interleaved data */ -#endif - curl_off_t infilesize; /* size of file to upload, -1 means unknown. Copied from set.filesize at start of operation */ -#if defined(USE_HTTP2) || defined(USE_HTTP3) - struct Curl_data_priority priority; /* shallow copy of data->set */ -#endif - curl_read_callback fread_func; /* read callback/function */ void *in; /* CURLOPT_READDATA */ CURLU *uh; /* URL handle for the current parsed URL */ @@ -658,6 +633,17 @@ struct UrlState { } aptr; #ifndef CURL_DISABLE_HTTP struct http_negotiation http_neg; +#endif +#ifndef CURL_DISABLE_RTSP + /* This RTSP state information survives requests and connections */ + uint8_t rtp_channel_mask[32]; /* for the correctness checking of the + interleaved data */ + uint32_t rtsp_next_client_CSeq; /* the session's next client CSeq */ + uint32_t rtsp_next_server_CSeq; /* the session's next server CSeq */ + uint32_t rtsp_CSeq_recv; /* most recent CSeq received */ +#endif +#if defined(USE_HTTP2) || defined(USE_HTTP3) + int weight; /* shallow copy of data->set */ #endif uint16_t followlocation; /* redirect counter */ uint8_t retrycount; /* number of retries on a new connection, up to @@ -665,6 +651,9 @@ struct UrlState { uint8_t httpreq; /* Curl_HttpReq; what kind of HTTP request (if any) is this */ +#ifdef USE_OPENSSL + BIT(provider_loaded); +#endif /* USE_OPENSSL */ BIT(really_alive); /* transfer is really alive in multi, passed INIT */ BIT(this_is_a_follow); /* this is a followed Location: request */ BIT(refused_stream); /* this was refused, try again */ @@ -869,7 +858,6 @@ struct UserDefined { void *writeheader; /* write the header to this if non-NULL */ uint32_t httpauth; /* kind of HTTP authentication to use (bitmask) */ uint32_t proxyauth; /* kind of proxy authentication to use (bitmask) */ - uint8_t httpsig_algorithm; /* CURLHTTPSIG_* algorithm for RFC 9421 */ void *postfields; /* if POST, set the fields' values here */ curl_seek_callback seek_func; /* function that seeks the input */ curl_off_t postfieldsize; /* if POST, this might have a size to use instead @@ -949,9 +937,6 @@ struct UserDefined { curl_off_t max_filesize; /* Maximum file size to download */ #ifndef CURL_DISABLE_FTP timediff_t accepttimeout; /* in milliseconds, 0 means no timeout */ - uint8_t ftp_filemethod; /* how to get to a file: curl_ftpfile */ - uint8_t ftpsslauth; /* what AUTH XXX to try: curl_ftpauth */ - uint8_t ftp_ccc; /* FTP CCC options: curl_ftpccc */ #endif #if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) struct curl_slist *quote; /* after connection is established */ @@ -968,9 +953,9 @@ struct UserDefined { uint32_t ssh_auth_types; /* allowed SSH auth types */ uint32_t new_directory_perms; /* when creating remote dirs */ #endif - uint32_t new_file_perms; /* when creating remote files */ char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */ struct curl_blob *blobs[BLOB_LAST]; + uint32_t new_file_perms; /* when creating remote files */ #ifdef USE_IPV6 uint32_t scope_id; /* Scope id for IPv6 */ #endif @@ -978,8 +963,6 @@ struct UserDefined { curl_prot_t redir_protocols; #ifndef CURL_DISABLE_RTSP void *rtp_out; /* write RTP to this if non-NULL */ - /* Common RTSP header options */ - unsigned char rtspreq; /* RTSP request type */ #endif #ifndef CURL_DISABLE_FTP curl_chunk_bgn_callback chunk_bgn; /* called before part of transfer @@ -997,13 +980,6 @@ struct UserDefined { timediff_t happy_eyeballs_timeout; /* ms, 0 is a valid value */ timediff_t server_response_timeout; /* ms, 0 means no timeout */ timediff_t shutdowntimeout; /* ms, 0 means default timeout */ - int tcp_keepidle; /* seconds in idle before sending keepalive probe */ - int tcp_keepintvl; /* seconds between TCP keepalive probes */ - int tcp_keepcnt; /* maximum number of keepalive probes */ - -#if defined(USE_HTTP2) || defined(USE_HTTP3) - struct Curl_data_priority priority; -#endif curl_resolver_start_callback resolver_start; /* optional callback called before resolver start */ void *resolver_start_client; /* pointer to pass to resolver start callback */ @@ -1017,7 +993,16 @@ struct UserDefined { #ifndef CURL_DISABLE_SMTP struct curl_slist *mail_rcpt; /* linked list of mail recipients */ #endif + int tcp_keepidle; /* seconds in idle before sending keepalive probe */ + int tcp_keepintvl; /* seconds between TCP keepalive probes */ + int tcp_keepcnt; /* maximum number of keepalive probes */ + uint32_t maxconnects; /* Max idle connections in the connection cache */ +#if defined(USE_HTTP2) || defined(USE_HTTP3) + /* Priority information for an easy handle in relation to others on the same + connection. */ + int weight; +#endif short maxredirs; /* maximum no. of http(s) redirects to follow, set to -1 for infinity */ uint16_t expect_100_timeout; /* in milliseconds */ @@ -1032,6 +1017,9 @@ struct UserDefined { #ifndef CURL_DISABLE_TFTP uint16_t tftp_blksize; /* in bytes, 0 means use default */ #endif +#ifndef CURL_DISABLE_RTSP + uint8_t rtspreq; /* RTSP request type */ +#endif #ifdef USE_ECH uint8_t tls_ech; /* TLS ECH configuration */ #endif @@ -1045,6 +1033,12 @@ struct UserDefined { */ uint8_t ftp_create_missing_dirs; #endif +#ifndef CURL_DISABLE_FTP + uint8_t ftp_filemethod; /* how to get to a file: curl_ftpfile */ + uint8_t ftpsslauth; /* what AUTH XXX to try: curl_ftpauth */ + uint8_t ftp_ccc; /* FTP CCC options: curl_ftpccc */ +#endif + uint8_t httpsig_algorithm; /* CURLHTTPSIG_* algorithm for RFC 9421 */ uint8_t use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or IMAP or POP3 or others! (type: curl_usessl)*/ uint8_t timecondition; /* kind of time comparison: curl_TimeCond */