On 9/21/23 3:15 PM, yla...@apache.org wrote:
> Author: ylavic
> Date: Thu Sep 21 13:15:35 2023
> New Revision: 1912459
> 
> URL: http://svn.apache.org/viewvc?rev=1912459&view=rev
> Log:
> mod_proxy: Handle backend address renewal with address_ttl= parameter.
> 
> Define a new proxy_address struct holding the current/latest sockaddr in use
> by each proxy worker and conn. Since backend addresses can be updated when
> their TTL expires and while connections are being processed, each address is
> refcounted and freed only when the last worker (or conn) using it grabs the
> new one.
> 
> The lifetime of the addresses is handled at a single place by the new
> ap_proxy_determine_address() function. It guarantees to bind the 
> current/latest
> backend address to the passed in conn (or do nothing if it's up to date 
> already).
> The function is called indirectly by ap_proxy_determine_connection() for the
> proxy modules that use it, or directly by mod_proxy_ftp and mod_proxy_hcheck.
> It also is called eventually by ap_proxy_connect_backend() when connect()ing 
> all
> the current addresses fails, to check (PROXY_DETERMINE_ADDRESS_CHECK) if some
> new addrs are available.
> 
> This commit is also a rework of the lifetime of conn->addr, conn->hostname
> and conn->forward, using the conn->uds_pool and conn->fwd_pool for the cases
> where the backend is connected through a UDS socket and a remote CONNECT proxy
> respectively.
> 
> * include/ap_mmn.h:
>   Minor bump for new function/fields.
> 
> * modules/proxy/mod_proxy.h (struct proxy_address,
>                              ap_proxy_determine_addresss()):
>   Declare ap_proxy_determine_addresss() and opaque struct proxy_address,
>   new fields to structs proxy_conn_rec/proxy_worker_shared/proxy_worker.
> 
> * modules/proxy/mod_proxy.c (set_worker_param):
>   Parse/set the new worker->address_ttl parameter.
> 
> * modules/proxy/proxy_util.c (proxy_util_register_hooks(),
>                               ap_proxy_initialize_worker(),
>                               ap_proxy_connection_reusable(),
>                               ap_proxyerror(), proxyerror_core(),
>                               init_conn_pool(), make_conn_subpool(),
>                               connection_make(), connection_cleanup(),
>                               connection_constructor()):
>  Initialize *proxy_start_time in proxy_util_register_hooks() as the epoch
>  from which expiration times are relative (i.e. seconds stored in an uint32_t
>  for atomic changes).
>  Make sure worker->s->is_address_reusable and worker->s->disablereuse are
>  consistant in ap_proxy_initialize_worker(), thus no need to check for both
>  in ap_proxy_connection_reusable().
>  New proxyerror_core() helper taking an apr_status_t to log, wrap in
>  ap_proxyerror().
>  New make_conn_subpool() to create worker->cp->{pool,dns} with their own
>  allocator.
>  New connection_make() helper to factorize code in connection_cleanup() and
>  connection_constructor().
> 
> * modules/proxy/proxy_util.c (proxy_address_inc(), proxy_address_dec(),
>                               proxy_address_cleanup(), 
> proxy_address_set_expired(),
>                               worker_address_get(), worker_address_set(),
>                               worker_address_resolve(), proxy_addrs_equal(),
>                               ap_proxy_determine_address(),
>                               ap_proxy_determine_connection(),
>                               ap_proxy_connect_backend()):
>  Implement ap_proxy_determine_address() using the above helpers for atomic 
> changes,
>  and call it from ap_proxy_determine_connection() and 
> ap_proxy_connect_backend().
> 
> * modules/proxy/mod_proxy_ftp.c (proxy_ftp_handler):
>   Use ap_proxy_determine_address() and use the returned backend->addr.
> 
> * modules/proxy/mod_proxy_hcheck.c (hc_determine_connection, hc_get_backend,
>                                     hc_init_worker, hc_watchdog_callback):
>   Use ap_proxy_determine_address() in hc_determine_connection() and call the
>   latter from hc_get_backend(), replace hc_init_worker() by hc_init_baton()
>   which now calls hc_get_hcworker() and hc_get_backend() to resolve the first
>   address at init time.
> 
> * modules/proxy/mod_proxy_http.c (proxy_http_handler):
>   Use backend->addr and ->hostname instead of worker->cp->addr and
>   worker->s->hostname_ex respectively.
> 
> * modules/proxy/mod_proxy_ajp.c (ap_proxy_ajp_request):
>   Use backend->addr and ->hostname instead of worker->cp->addr and
>   worker->s->hostname_ex respectively.
> 
> 
> Closes #367
> 
> 
> Modified:
>     httpd/httpd/trunk/include/ap_mmn.h
>     httpd/httpd/trunk/modules/proxy/mod_proxy.c
>     httpd/httpd/trunk/modules/proxy/mod_proxy.h
>     httpd/httpd/trunk/modules/proxy/mod_proxy_ajp.c
>     httpd/httpd/trunk/modules/proxy/mod_proxy_ftp.c
>     httpd/httpd/trunk/modules/proxy/mod_proxy_hcheck.c
>     httpd/httpd/trunk/modules/proxy/mod_proxy_http.c
>     httpd/httpd/trunk/modules/proxy/proxy_util.c
> 

> Modified: httpd/httpd/trunk/modules/proxy/proxy_util.c
> URL: 
> http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/proxy_util.c?rev=1912459&r1=1912458&r2=1912459&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/modules/proxy/proxy_util.c (original)
> +++ httpd/httpd/trunk/modules/proxy/proxy_util.c Thu Sep 21 13:15:35 2023

> @@ -2683,56 +3116,83 @@ ap_proxy_determine_connection(apr_pool_t
>       *      to check host and port on the conn and be careful about
>       *      spilling the cached addr from the worker.
>       */
> -    uds_path = (*worker->s->uds_path ? worker->s->uds_path : 
> apr_table_get(r->notes, "uds_path"));
> +    uds_path = (*worker->s->uds_path
> +                ? worker->s->uds_path
> +                : apr_table_get(r->notes, "uds_path"));
>      if (uds_path) {
> -        if (conn->uds_path == NULL) {
> -            /* use (*conn)->pool instead of worker->cp->pool to match 
> lifetime */
> -            conn->uds_path = apr_pstrdup(conn->pool, uds_path);
> -        }
> -        if (conn->uds_path) {
> -            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02545)
> -                         "%s: has determined UDS as %s",
> -                         uri->scheme, conn->uds_path);
> -        }
> -        else {
> -            /* should never happen */
> -            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02546)
> -                         "%s: cannot determine UDS (%s)",
> -                         uri->scheme, uds_path);
> -
> -        }
> -        /*
> -         * In UDS cases, some structs are NULL. Protect from de-refs
> -         * and provide info for logging at the same time.
> -         */
> -        if (!conn->addr) {
> -            apr_sockaddr_t *sa;
> -            apr_sockaddr_info_get(&sa, NULL, APR_UNSPEC, 0, 0, conn->pool);
> -            conn->addr = sa;
> +        if (!conn->uds_path || strcmp(conn->uds_path, uds_path) != 0) {
> +            apr_pool_t *pool = conn->pool;
> +            if (conn->uds_path) {
> +                address_cleanup(conn);
> +                if (!conn->uds_pool) {
> +                    apr_pool_create(&conn->uds_pool, worker->cp->dns_pool);
> +                }
> +                pool = conn->uds_pool;
> +            }
> +            /*
> +             * In UDS cases, some structs are NULL. Protect from de-refs
> +             * and provide info for logging at the same time.
> +             */
> +#if APR_HAVE_SOCKADDR_UN
> +            apr_sockaddr_info_get(&conn->addr, uds_path, APR_UNIX, 0, 0, 
> pool);
> +            if (conn->addr && conn->addr->hostname) {
> +                conn->uds_path = conn->addr->hostname;
> +            }
> +            else {
> +                conn->uds_path = apr_pstrdup(pool, uds_path);
> +            }
> +#else
> +            apr_sockaddr_info_get(&conn->addr, NULL, APR_UNSPEC, 0, 0, pool);
> +            conn->uds_path = apr_pstrdup(pool, uds_path);
> +#endif
> +            conn->hostname = apr_pstrdup(pool, uri->hostname);
> +            conn->port = uri->port;
>          }
> -        conn->hostname = "httpd-UDS";
> -        conn->port = 0;
> +        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02545)
> +                     "%s: has determined UDS as %s (for %s:%hu)",
> +                     uri->scheme, conn->uds_path, conn->hostname, 
> conn->port);
>      }
>      else {
> -        int will_reuse = worker->s->is_address_reusable && 
> !worker->s->disablereuse;
> -        if (!conn->hostname || !will_reuse) {
> -            if (proxyname) {
> -                conn->hostname = apr_pstrdup(conn->pool, proxyname);
> -                conn->port = proxyport;
> +        const char *hostname = uri->hostname;
> +        apr_port_t hostport = uri->port;
> +
> +        if (proxyname) {
> +            forward_info *forward;
> +
> +            hostname = proxyname;
> +            hostport = proxyport;
> +
> +            /* Reset forward info if they changed */
> +            if (conn->is_ssl
> +                && (!(forward = conn->forward)
> +                    || forward->target_port != uri->port
> +                    || ap_cstr_casecmp(forward->target_host,
> +                                       uri->hostname) != 0)) {
> +                apr_pool_t *fwd_pool = conn->pool;
> +                if (worker->s->is_address_reusable) {
> +                    if (conn->fwd_pool) {
> +                        apr_pool_clear(conn->fwd_pool);
> +                    }
> +                    else {
> +                        apr_pool_create(&conn->fwd_pool, conn->pool);
> +                    }


Don't we need to

fwd_pool = conn->fwd_pool

??

> +                }
> +                forward = apr_pcalloc(fwd_pool, sizeof(forward_info));
> +                conn->forward = forward;
> +
>                  /*
> -                 * If we have a forward proxy and the protocol is HTTPS,
> +                 * If we have a remote proxy and the protocol is HTTPS,
>                   * then we need to prepend a HTTP CONNECT request before
>                   * sending our actual HTTPS requests.
>                   * Save our real backend data for using it later during HTTP 
> CONNECT.
>                   */
> -                if (conn->is_ssl) {
> +                {
>                      const char *proxy_auth;
>  
> -                    forward_info *forward = apr_pcalloc(conn->pool, 
> sizeof(forward_info));
> -                    conn->forward = forward;
>                      forward->use_http_connect = 1;
> -                    forward->target_host = apr_pstrdup(conn->pool, 
> uri->hostname);
> +                    forward->target_host = apr_pstrdup(fwd_pool, 
> uri->hostname);
>                      forward->target_port = uri->port;
> +
>                      /* Do we want to pass Proxy-Authorization along?
>                       * If we haven't used it, then YES
>                       * If we have used it then MAYBE: RFC2616 says we MAY 
> propagate it.

Regards

RĂ¼diger

Reply via email to