]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Make sure that we don't increase balancer worker count on
authorMladen Turk <mturk@apache.org>
Tue, 28 Sep 2004 16:35:29 +0000 (16:35 +0000)
committerMladen Turk <mturk@apache.org>
Tue, 28 Sep 2004 16:35:29 +0000 (16:35 +0000)
gracefull restart. Thanks to Christian...again.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@105318 13f79535-47bb-0310-9956-ffa450edef68

modules/proxy/mod_proxy.c
modules/proxy/mod_proxy.h
modules/proxy/proxy_balancer.c
modules/proxy/proxy_util.c

index c5bf0712b44e287818838b8a29ce9fd32a183c39..fb2375803e55b5bb8b186cf3459b40b3416911d5 100644 (file)
@@ -1807,6 +1807,8 @@ static int proxy_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
 {
     APR_OPTIONAL_HOOK(ap, status_hook, proxy_status_hook, NULL, NULL,
                       APR_HOOK_MIDDLE);
+    /* Reset workers count on gracefull restart */ 
+    proxy_lb_workers = 0;
     return OK;
 }
 
index a510d2e8d3edcb677b846ad3a7014d03ffca4edc..20b26dad4863c4ad415e5a265de34d4a38d11a83 100644 (file)
-/* Copyright 1999-2004 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MOD_PROXY_H
-#define MOD_PROXY_H 
-
-/*
- * Main include file for the Apache proxy
- */
-
-/*
-
-   Also note numerous FIXMEs and CHECKMEs which should be eliminated.
-
-   This code is once again experimental!
-
-   Things to do:
-
-   1. Make it completely work (for FTP too)
-
-   2. HTTP/1.1
-
-   Chuck Murcko <chuck@topsail.org> 02-06-01
-
- */
-
-#define CORE_PRIVATE
-
-#include "apr_hooks.h"
-#include "apr.h"
-#include "apr_lib.h"
-#include "apr_strings.h"
-#include "apr_buckets.h"
-#include "apr_md5.h"
-#include "apr_network_io.h"
-#include "apr_pools.h"
-#include "apr_strings.h"
-#include "apr_uri.h"
-#include "apr_date.h"
-#include "apr_strmatch.h"
-#include "apr_fnmatch.h"
-#include "apr_reslist.h"
-#define APR_WANT_STRFUNC
-#include "apr_want.h"
-
-#include "httpd.h"
-#include "http_config.h"
-#include "ap_config.h"
-#include "http_core.h"
-#include "http_protocol.h"
-#include "http_request.h"
-#include "http_vhost.h"
-#include "http_main.h"
-#include "http_log.h"
-#include "http_connection.h"
-#include "util_filter.h"
-#include "util_ebcdic.h"
-
-#if APR_HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#if APR_HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-
-/* for proxy_canonenc() */
-enum enctype {
-    enc_path, enc_search, enc_user, enc_fpath, enc_parm
-};
-
-#if APR_CHARSET_EBCDIC
-#define CRLF   "\r\n"
-#else /*APR_CHARSET_EBCDIC*/
-#define CRLF   "\015\012"
-#endif /*APR_CHARSET_EBCDIC*/
-
-/* default Max-Forwards header setting */
-#define DEFAULT_MAX_FORWARDS    10
-
-/* static information about a remote proxy */
-struct proxy_remote {
-    const char *scheme;     /* the schemes handled by this proxy, or '*' */
-    const char *protocol;   /* the scheme used to talk to this proxy */
-    const char *hostname;   /* the hostname of this proxy */
-    apr_port_t  port;       /* the port for this proxy */
-    regex_t *regexp;        /* compiled regex (if any) for the remote */
-    int use_regex;          /* simple boolean. True if we have a regex pattern */
-};
-
-struct proxy_alias {
-    const char  *real;
-    const char  *fake;
-};
-
-struct dirconn_entry {
-    char *name;
-    struct in_addr addr, mask;
-    struct apr_sockaddr_t *hostaddr;
-    int (*matcher) (struct dirconn_entry * This, request_rec *r);
-};
-
-struct noproxy_entry {
-    const char *name;
-    struct apr_sockaddr_t *addr;
-};
-
-typedef struct proxy_balancer  proxy_balancer;
-typedef struct proxy_worker    proxy_worker;
-typedef struct proxy_conn_pool proxy_conn_pool;
-
-typedef struct {
-    apr_array_header_t *proxies;
-    apr_array_header_t *sec_proxy;
-    apr_array_header_t *aliases;
-    apr_array_header_t *raliases;
-    apr_array_header_t *noproxies;
-    apr_array_header_t *dirconn;
-    apr_array_header_t *allowed_connect_ports;
-    apr_array_header_t *workers;
-    apr_array_header_t *balancers;
-    proxy_worker       *forward;    /* forward proxy worker */
-    const char *domain;     /* domain name to use in absence of a domain name in the request */
-    int req;                /* true if proxy requests are enabled */
-    char req_set;
-    enum {
-      via_off,
-      via_on,
-      via_block,
-      via_full
-    } viaopt;                   /* how to deal with proxy Via: headers */
-    char viaopt_set;
-    apr_size_t recv_buffer_size;
-    char recv_buffer_size_set;
-    apr_size_t io_buffer_size;
-    char io_buffer_size_set;
-    long maxfwd;
-    char maxfwd_set;
-    /** 
-     * the following setting masks the error page
-     * returned from the 'proxied server' and just 
-     * forwards the status code upwards.
-     * This allows the main server (us) to generate
-     * the error page, (so it will look like a error
-     * returned from the rest of the system 
-     */
-    int error_override;
-    int error_override_set;
-    int preserve_host;
-    int preserve_host_set;
-    apr_interval_time_t timeout;
-    char timeout_set;
-    enum {
-      bad_error,
-      bad_ignore,
-      bad_body
-    } badopt;                   /* how to deal with bad headers */
-    char badopt_set;
-/* putting new stuff on the end maximises binary back-compatibility.
- * the strmatch_patterns are really a const just to have a
- * case-independent strstr.
- */
-    apr_array_header_t* cookie_paths;
-    apr_array_header_t* cookie_domains;
-    const apr_strmatch_pattern* cookie_path_str;
-    const apr_strmatch_pattern* cookie_domain_str;
-    enum {
-        status_off,
-        status_on,
-        status_full
-    } proxy_status;             /* Status display options */
-    char proxy_status_set;
-    apr_pool_t *pool;           /* Pool used for allocating this struct */
-} proxy_server_conf;
-
-
-typedef struct {
-    const char *p;            /* The path */
-    int         p_is_fnmatch; /* Is this path an fnmatch candidate? */
-    regex_t    *r;            /* Is this a regex? */
-} proxy_dir_conf;
-
-typedef struct {
-    conn_rec     *connection;
-    const char   *hostname;
-    apr_port_t   port;
-    int          is_ssl;
-    apr_pool_t   *pool;     /* Subpool used for creating socket */
-    apr_socket_t *sock;     /* Connection socket */
-    apr_sockaddr_t *addr;   /* Preparsed remote address info */
-    apr_uint32_t flags;     /* Conection flags */
-    int          close;     /* Close 'this' connection */
-    int          close_on_recycle; /* Close the connection when returning to pool */
-    proxy_worker *worker;   /* Connection pool this connection belogns to */
-    void         *data;     /* per scheme connection data */
-} proxy_conn_rec;
-
-typedef struct {
-        float cache_completion; /* completion percentage */
-        int content_length; /* length of the content */
-} proxy_completion;
-
-/* Connection pool */
-struct proxy_conn_pool {
-    apr_pool_t     *pool;   /* The pool used in constructor and destructor calls */
-    apr_sockaddr_t *addr;   /* Preparsed remote address info */
-#if APR_HAS_THREADS
-    apr_reslist_t  *res;    /* Connection resource list */
-#endif
-    proxy_conn_rec *conn;   /* Single connection for prefork mpm's */
-};
-
-/* woker status flags */
-#define PROXY_WORKER_INITIALIZED    0x0001
-#define PROXY_WORKER_IGNORE_ERRORS  0x0002
-#define PROXY_WORKER_IN_SHUTDOWN    0x0010
-#define PROXY_WORKER_DISABLED       0x0020
-#define PROXY_WORKER_IN_ERROR       0x0040
-
-#define PROXY_WORKER_IS_USABLE(f)   (!((f)->s->status & 0x00F0))
-
-/* default worker retry timeout in seconds */
-#define PROXY_WORKER_DEFAULT_RETRY  60
-#define PROXY_WORKER_MAX_ROUTE_SIZ  63
-
-/* Runtime worker status informations. Shared in scoreboard */
-typedef struct {
-    int             status;
-    apr_time_t      error_time; /* time of the last error */
-    int             retries;    /* number of retries on this worker */
-    int             lbstatus;   /* Current lbstatus */
-    int             lbfactor;   /* dynamic lbfactor */
-    apr_off_t       transfered; /* Number of bytes transfered to remote */
-    apr_off_t       readed;     /* Number of bytes readed from remote */
-    apr_size_t      elected;    /* Number of times the worker was elected */
-    char            route[PROXY_WORKER_MAX_ROUTE_SIZ+1];
-    char            redirect[PROXY_WORKER_MAX_ROUTE_SIZ+1];
-} proxy_worker_stat;
-
-/* Worker configuration */
-struct proxy_worker {
-    int             id;         /* scoreboard id */
-    apr_interval_time_t retry;  /* retry interval */
-    int             lbfactor;   /* initial load balancing factor */
-    const char      *name;
-    const char      *scheme;    /* scheme to use ajp|http|https */
-    const char      *hostname;  /* remote backend address */
-    const char      *route;     /* balancing route */
-    const char      *redirect;  /* temporary balancing redirection route */
-    apr_port_t      port;
-    int             min;        /* Desired minimum number of available connections */
-    int             smax;       /* Soft maximum on the total number of connections */
-    int             hmax;       /* Hard maximum on the total number of connections */
-    apr_interval_time_t ttl;    /* maximum amount of time in seconds a connection
-                                 * may be available while exceeding the soft limit */
-    apr_interval_time_t timeout; /* connection timeout */
-    char                timeout_set;
-    apr_interval_time_t acquire; /* acquire timeout when the maximum number of connections is exceeded */
-    char                acquire_set;
-    apr_size_t          recv_buffer_size;
-    char                recv_buffer_size_set;
-    apr_size_t          io_buffer_size;
-    char                io_buffer_size_set;
-    char                keepalive;
-    char                keepalive_set;
-    proxy_conn_pool     *cp;        /* Connection pool to use */
-    proxy_worker_stat   *s;         /* Shared data */
-    void                *opaque;    /* per scheme worker data */
-};
-
-struct proxy_balancer {
-    apr_array_header_t *workers; /* array of proxy_workers */
-    const char *name;            /* name of the load balancer */
-    const char *sticky;          /* sticky session identifier */
-    int         sticky_force;    /* Disable failover for sticky sessions */
-    apr_interval_time_t timeout; /* Timeout for waiting on free connection */
-    int                 max_attempts; /* Number of attempts before failing */
-    char                max_attempts_set;
-
-    /* XXX: Perhaps we will need the proc mutex too.
-     * Altrough we are only using arithmetic operations
-     * it may lead to a incorrect calculations.
-     * For now use only the thread mutex.
-     */
-#if APR_HAS_THREADS
-    apr_thread_mutex_t  *mutex;  /* Thread lock for updating lb params */
-#endif
-};
-
-/* hooks */
-
-/* Create a set of PROXY_DECLARE(type), PROXY_DECLARE_NONSTD(type) and 
- * PROXY_DECLARE_DATA with appropriate export and import tags for the platform
- */
-#if !defined(WIN32)
-#define PROXY_DECLARE(type)            type
-#define PROXY_DECLARE_NONSTD(type)     type
-#define PROXY_DECLARE_DATA
-#elif defined(PROXY_DECLARE_STATIC)
-#define PROXY_DECLARE(type)            type __stdcall
-#define PROXY_DECLARE_NONSTD(type)     type
-#define PROXY_DECLARE_DATA
-#elif defined(PROXY_DECLARE_EXPORT)
-#define PROXY_DECLARE(type)            __declspec(dllexport) type __stdcall
-#define PROXY_DECLARE_NONSTD(type)     __declspec(dllexport) type
-#define PROXY_DECLARE_DATA             __declspec(dllexport)
-#else
-#define PROXY_DECLARE(type)            __declspec(dllimport) type __stdcall
-#define PROXY_DECLARE_NONSTD(type)     __declspec(dllimport) type
-#define PROXY_DECLARE_DATA             __declspec(dllimport)
-#endif
-
-/**
- * Hook an optional proxy hook.  Unlike static hooks, this uses a macro
- * instead of a function.
- */
-#define PROXY_OPTIONAL_HOOK(name,fn,pre,succ,order) \
-        APR_OPTIONAL_HOOK(proxy,name,fn,pre,succ,order)
-
-APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, scheme_handler, (request_rec *r, 
-                          proxy_worker *worker, proxy_server_conf *conf, char *url, 
-                          const char *proxyhost, apr_port_t proxyport))
-APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, canon_handler, (request_rec *r, 
-                          char *url))
-
-APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, create_req, (request_rec *r, request_rec *pr))
-APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, fixups, (request_rec *r)) 
-
-/**
- * pre request hook.
- * It will return the most suitable worker at the moment
- * and coresponding balancer.
- * The url is rewritten from balancer://cluster/uri to scheme://host:port/uri
- * and then the scheme_handler is called.
- *
- */
-APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, pre_request, (proxy_worker **worker,
-                          proxy_balancer **balancer,
-                          request_rec *r,
-                          proxy_server_conf *conf, char **url))                          
-/**
- * post request hook.
- * It is called after request for updating runtime balancer status.
- */
-APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, post_request, (proxy_worker *worker,
-                          proxy_balancer *balancer, request_rec *r,
-                          proxy_server_conf *conf))
-
-
-/* proxy_util.c */
-
-PROXY_DECLARE(request_rec *)ap_proxy_make_fake_req(conn_rec *c, request_rec *r);
-PROXY_DECLARE(int) ap_proxy_hex2c(const char *x);
-PROXY_DECLARE(void) ap_proxy_c2hex(int ch, char *x);
-PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, enum enctype t,
-                                       int isenc);
-PROXY_DECLARE(char *)ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp,
-                                           char **passwordp, char **hostp, apr_port_t *port);
-PROXY_DECLARE(const char *)ap_proxy_date_canon(apr_pool_t *p, const char *x);
-PROXY_DECLARE(int) ap_proxy_liststr(const char *list, const char *val);
-PROXY_DECLARE(char *)ap_proxy_removestr(apr_pool_t *pool, const char *list, const char *val);
-PROXY_DECLARE(int) ap_proxy_hex2sec(const char *x);
-PROXY_DECLARE(void) ap_proxy_sec2hex(int t, char *y);
-PROXY_DECLARE(int) ap_proxyerror(request_rec *r, int statuscode, const char *message);
-PROXY_DECLARE(int) ap_proxy_is_ipaddr(struct dirconn_entry *This, apr_pool_t *p);
-PROXY_DECLARE(int) ap_proxy_is_domainname(struct dirconn_entry *This, apr_pool_t *p);
-PROXY_DECLARE(int) ap_proxy_is_hostname(struct dirconn_entry *This, apr_pool_t *p);
-PROXY_DECLARE(int) ap_proxy_is_word(struct dirconn_entry *This, apr_pool_t *p);
-PROXY_DECLARE(int) ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf, apr_sockaddr_t *uri_addr);
-PROXY_DECLARE(int) ap_proxy_pre_http_request(conn_rec *c, request_rec *r);
-PROXY_DECLARE(apr_status_t) ap_proxy_string_read(conn_rec *c, apr_bucket_brigade *bb, char *buff, size_t bufflen, int *eos);
-PROXY_DECLARE(void) ap_proxy_table_unmerge(apr_pool_t *p, apr_table_t *t, char *key);
-/* DEPRECATED (will be replaced with ap_proxy_connect_backend */
-PROXY_DECLARE(int) ap_proxy_connect_to_backend(apr_socket_t **, const char *, apr_sockaddr_t *, const char *, proxy_server_conf *, server_rec *, apr_pool_t *);
-PROXY_DECLARE(int) ap_proxy_ssl_enable(conn_rec *c);
-PROXY_DECLARE(int) ap_proxy_ssl_disable(conn_rec *c);
-
-/* Connection pool API */
-/**
- * Get the worker from proxy configuration
- * @param p     memory pool used for finding worker
- * @param conf  current proxy server configuration
- * @param url   url to find the worker from
- * @return      proxy_worker or NULL if not found
- */
-PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
-                                                  proxy_server_conf *conf,
-                                                  const char *url);
-/**
- * Add the worker to proxy configuration
- * @param worker the new worker
- * @param p      memory pool to allocate worker from 
- * @param conf   current proxy server configuration
- * @param url    url containing worker name
- * @return       error message or NULL if successfull
- */
-PROXY_DECLARE(const char *) ap_proxy_add_worker(proxy_worker **worker,
-                                                apr_pool_t *p,
-                                                proxy_server_conf *conf,
-                                                const char *url);
-
-/**
- * Create new worker
- * @param p      memory pool to allocate worker from 
- * @return       new worker
- */
-PROXY_DECLARE(proxy_worker *) ap_proxy_create_worker(apr_pool_t *p);
-
-/**
- * Initize the worker's shared data
- * @param conf   current proxy server configuration
- * @param s      current server record
- * @param worker worker to initialize
- */
-PROXY_DECLARE(void) ap_proxy_initialize_worker_share(proxy_server_conf *conf,
-                                                     proxy_worker *worker);
-
-
-/**
- * Initize the worker
- * @param worker worker to initialize
- * @param p      memory pool to allocate worker from 
- * @param s      current server record
- * @return       APR_SUCCESS or error code
- */
-PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker,
-                                                       server_rec *s);
-/**
- * Get the balancer from proxy configuration
- * @param p     memory pool used for finding balancer
- * @param conf  current proxy server configuration
- * @param url   url to find the worker from. Has to have balancer:// prefix
- * @return      proxy_balancer or NULL if not found
- */
-PROXY_DECLARE(proxy_balancer *) ap_proxy_get_balancer(apr_pool_t *p,
-                                                      proxy_server_conf *conf,
-                                                      const char *url);
-/**
- * Add the balancer to proxy configuration
- * @param balancer the new balancer
- * @param p      memory pool to allocate balancer from 
- * @param conf   current proxy server configuration
- * @param url    url containing balancer name
- * @return       error message or NULL if successfull
- */
-PROXY_DECLARE(const char *) ap_proxy_add_balancer(proxy_balancer **balancer,
-                                                  apr_pool_t *p,
-                                                  proxy_server_conf *conf,
-                                                  const char *url);
-
-/**
- * Add the worker to the balancer
- * @param pool     memory pool for adding worker 
- * @param balancer balancer to add to
- * @param balancer worker to add
- * @note Single worker can be added to multiple balancers.
- */
-PROXY_DECLARE(void) ap_proxy_add_worker_to_balancer(apr_pool_t *pool,
-                                                    proxy_balancer *balancer,
-                                                    proxy_worker *worker);
-/**
- * Get the most suitable worker and(or) balancer for the request
- * @param worker   worker used for processing request
- * @param balancer balancer used for processing request
- * @param r        current request
- * @param conf     current proxy server configuration
- * @param url      request url that balancer can rewrite.
- * @return         OK or  HTTP_XXX error 
- * @note It calls balancer pre_request hook if the url starts with balancer://
- * The balancer then rewrites the url to particular worker, like http://host:port
- */
-PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
-                                        proxy_balancer **balancer,
-                                        request_rec *r,
-                                        proxy_server_conf *conf,
-                                        char **url);
-/**
- * Post request worker and balancer cleanup
- * @param worker   worker used for processing request
- * @param balancer balancer used for processing request
- * @param r        current request
- * @param conf     current proxy server configuration
- * @return         OK or  HTTP_XXX error
- * @note When ever the pre_request is called, the post_request has to be
- * called too. 
- */
-PROXY_DECLARE(int) ap_proxy_post_request(proxy_worker *worker,
-                                         proxy_balancer *balancer,
-                                         request_rec *r,
-                                         proxy_server_conf *conf);
-/**
- * Deternime backend hostname and port
- * @param p       memory pool used for processing
- * @param r       current request
- * @param conf    current proxy server configuration
- * @param worker  worker used for processing request
- * @param conn    proxy connection struct
- * @param uri     processed uri
- * @param url     request url
- * @param proxyname are we connecting directly or via s proxy
- * @param proxyport proxy host port
- * @param server_portstr Via headers server port
- * @param server_portstr_size size of the server_portstr buffer
- * @return         OK or HTTP_XXX error
- */                                         
-PROXY_DECLARE(int) ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
-                                                 proxy_server_conf *conf,
-                                                 proxy_worker *worker,
-                                                 proxy_conn_rec *conn,
-                                                 apr_uri_t *uri,
-                                                 char **url,
-                                                 const char *proxyname,
-                                                 apr_port_t proxyport,
-                                                 char *server_portstr,
-                                                 int server_portstr_size);
-/**
- * Mark a worker for retry
- * @param proxy_function calling proxy scheme (http, ajp, ...)
- * @param conf    current proxy server configuration
- * @param worker  worker used for retrying
- * @param s       current server record
- * @return        OK if marked for retry, DECLINED otherwise
- * @note Worker will be marker for retry if the time of the last retry
- * has been ellapsed. In case there is no retry option set, defaults to
- * number_of_retries seconds.
- */                                         
-PROXY_DECLARE(int) ap_proxy_retry_worker(const char *proxy_function,
-                                         proxy_worker *worker,
-                                         server_rec *s);
-/**
- * Acquire a connection from workers connection pool
- * @param proxy_function calling proxy scheme (http, ajp, ...)
- * @param conn    acquired connection
- * @param worker  worker used for obtaining connection
- * @param s       current server record
- * @return        OK or HTTP_XXX error
- * @note If the number of connections is exhaused the function will
- * block untill the timeout is reached.
- */                                         
-PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function,
-                                               proxy_conn_rec **conn,
-                                               proxy_worker *worker,
-                                               server_rec *s);
-/**
- * Release a connection back to worker connection pool
- * @param proxy_function calling proxy scheme (http, ajp, ...)
- * @param conn    acquired connection
- * @param s       current server record
- * @return        OK or HTTP_XXX error
- * @note The connection will be closed if conn->close_on_release is set
- */                                         
-PROXY_DECLARE(int) ap_proxy_release_connection(const char *proxy_function,
-                                               proxy_conn_rec *conn,
-                                               server_rec *s);
-/**
- * Make a connection to the backend
- * @param proxy_function calling proxy scheme (http, ajp, ...)
- * @param conn    acquired connection
- * @param worker  connection worker
- * @param s       current server record
- * @return        OK or HTTP_XXX error
- * @note In case the socket already exists for conn, just check the link
- * status.
- */                                         
-PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
-                                            proxy_conn_rec *conn,
-                                            proxy_worker *worker,
-                                            server_rec *s);
-/**
- * Make a connection record for backend connection
- * @param proxy_function calling proxy scheme (http, ajp, ...)
- * @param conn    acquired connection
- * @param c       client connection record
- * @param s       current server record
- * @return        OK or HTTP_XXX error
- */                                         
-PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function,
-                                              proxy_conn_rec *conn,
-                                              conn_rec *c, server_rec *s);
-
-/* Scoreboard */
-#if MODULE_MAGIC_NUMBER_MAJOR > 20020903
-#define PROXY_HAS_SCOREBOARD 1
-#else
-#define PROXY_HAS_SCOREBOARD 0
-#endif
-/* The number of dynamic balancers that can be added */
-#define PROXY_DYNAMIC_BALANCER_LIMIT    16
-int ap_proxy_lb_workers(void);
-
-/* For proxy_util */
-extern module PROXY_DECLARE_DATA proxy_module;
-
-#endif /*MOD_PROXY_H*/
+/* Copyright 1999-2004 The Apache Software Foundation\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef MOD_PROXY_H\r
+#define MOD_PROXY_H \r
+\r
+/*\r
+ * Main include file for the Apache proxy\r
+ */\r
+\r
+/*\r
+\r
+   Also note numerous FIXMEs and CHECKMEs which should be eliminated.\r
+\r
+   This code is once again experimental!\r
+\r
+   Things to do:\r
+\r
+   1. Make it completely work (for FTP too)\r
+\r
+   2. HTTP/1.1\r
+\r
+   Chuck Murcko <chuck@topsail.org> 02-06-01\r
+\r
+ */\r
+\r
+#define CORE_PRIVATE\r
+\r
+#include "apr_hooks.h"\r
+#include "apr.h"\r
+#include "apr_lib.h"\r
+#include "apr_strings.h"\r
+#include "apr_buckets.h"\r
+#include "apr_md5.h"\r
+#include "apr_network_io.h"\r
+#include "apr_pools.h"\r
+#include "apr_strings.h"\r
+#include "apr_uri.h"\r
+#include "apr_date.h"\r
+#include "apr_strmatch.h"\r
+#include "apr_fnmatch.h"\r
+#include "apr_reslist.h"\r
+#define APR_WANT_STRFUNC\r
+#include "apr_want.h"\r
+\r
+#include "httpd.h"\r
+#include "http_config.h"\r
+#include "ap_config.h"\r
+#include "http_core.h"\r
+#include "http_protocol.h"\r
+#include "http_request.h"\r
+#include "http_vhost.h"\r
+#include "http_main.h"\r
+#include "http_log.h"\r
+#include "http_connection.h"\r
+#include "util_filter.h"\r
+#include "util_ebcdic.h"\r
+\r
+#if APR_HAVE_NETINET_IN_H\r
+#include <netinet/in.h>\r
+#endif\r
+#if APR_HAVE_ARPA_INET_H\r
+#include <arpa/inet.h>\r
+#endif\r
+\r
+/* for proxy_canonenc() */\r
+enum enctype {\r
+    enc_path, enc_search, enc_user, enc_fpath, enc_parm\r
+};\r
+\r
+#if APR_CHARSET_EBCDIC\r
+#define CRLF   "\r\n"\r
+#else /*APR_CHARSET_EBCDIC*/\r
+#define CRLF   "\015\012"\r
+#endif /*APR_CHARSET_EBCDIC*/\r
+\r
+/* default Max-Forwards header setting */\r
+#define DEFAULT_MAX_FORWARDS    10\r
+\r
+/* static information about a remote proxy */\r
+struct proxy_remote {\r
+    const char *scheme;     /* the schemes handled by this proxy, or '*' */\r
+    const char *protocol;   /* the scheme used to talk to this proxy */\r
+    const char *hostname;   /* the hostname of this proxy */\r
+    apr_port_t  port;       /* the port for this proxy */\r
+    regex_t *regexp;        /* compiled regex (if any) for the remote */\r
+    int use_regex;          /* simple boolean. True if we have a regex pattern */\r
+};\r
+\r
+struct proxy_alias {\r
+    const char  *real;\r
+    const char  *fake;\r
+};\r
+\r
+struct dirconn_entry {\r
+    char *name;\r
+    struct in_addr addr, mask;\r
+    struct apr_sockaddr_t *hostaddr;\r
+    int (*matcher) (struct dirconn_entry * This, request_rec *r);\r
+};\r
+\r
+struct noproxy_entry {\r
+    const char *name;\r
+    struct apr_sockaddr_t *addr;\r
+};\r
+\r
+typedef struct proxy_balancer  proxy_balancer;\r
+typedef struct proxy_worker    proxy_worker;\r
+typedef struct proxy_conn_pool proxy_conn_pool;\r
+\r
+typedef struct {\r
+    apr_array_header_t *proxies;\r
+    apr_array_header_t *sec_proxy;\r
+    apr_array_header_t *aliases;\r
+    apr_array_header_t *raliases;\r
+    apr_array_header_t *noproxies;\r
+    apr_array_header_t *dirconn;\r
+    apr_array_header_t *allowed_connect_ports;\r
+    apr_array_header_t *workers;\r
+    apr_array_header_t *balancers;\r
+    proxy_worker       *forward;    /* forward proxy worker */\r
+    const char *domain;     /* domain name to use in absence of a domain name in the request */\r
+    int req;                /* true if proxy requests are enabled */\r
+    char req_set;\r
+    enum {\r
+      via_off,\r
+      via_on,\r
+      via_block,\r
+      via_full\r
+    } viaopt;                   /* how to deal with proxy Via: headers */\r
+    char viaopt_set;\r
+    apr_size_t recv_buffer_size;\r
+    char recv_buffer_size_set;\r
+    apr_size_t io_buffer_size;\r
+    char io_buffer_size_set;\r
+    long maxfwd;\r
+    char maxfwd_set;\r
+    /** \r
+     * the following setting masks the error page\r
+     * returned from the 'proxied server' and just \r
+     * forwards the status code upwards.\r
+     * This allows the main server (us) to generate\r
+     * the error page, (so it will look like a error\r
+     * returned from the rest of the system \r
+     */\r
+    int error_override;\r
+    int error_override_set;\r
+    int preserve_host;\r
+    int preserve_host_set;\r
+    apr_interval_time_t timeout;\r
+    char timeout_set;\r
+    enum {\r
+      bad_error,\r
+      bad_ignore,\r
+      bad_body\r
+    } badopt;                   /* how to deal with bad headers */\r
+    char badopt_set;\r
+/* putting new stuff on the end maximises binary back-compatibility.\r
+ * the strmatch_patterns are really a const just to have a\r
+ * case-independent strstr.\r
+ */\r
+    apr_array_header_t* cookie_paths;\r
+    apr_array_header_t* cookie_domains;\r
+    const apr_strmatch_pattern* cookie_path_str;\r
+    const apr_strmatch_pattern* cookie_domain_str;\r
+    enum {\r
+        status_off,\r
+        status_on,\r
+        status_full\r
+    } proxy_status;             /* Status display options */\r
+    char proxy_status_set;\r
+    apr_pool_t *pool;           /* Pool used for allocating this struct */\r
+} proxy_server_conf;\r
+\r
+\r
+typedef struct {\r
+    const char *p;            /* The path */\r
+    int         p_is_fnmatch; /* Is this path an fnmatch candidate? */\r
+    regex_t    *r;            /* Is this a regex? */\r
+} proxy_dir_conf;\r
+\r
+typedef struct {\r
+    conn_rec     *connection;\r
+    const char   *hostname;\r
+    apr_port_t   port;\r
+    int          is_ssl;\r
+    apr_pool_t   *pool;     /* Subpool used for creating socket */\r
+    apr_socket_t *sock;     /* Connection socket */\r
+    apr_sockaddr_t *addr;   /* Preparsed remote address info */\r
+    apr_uint32_t flags;     /* Conection flags */\r
+    int          close;     /* Close 'this' connection */\r
+    int          close_on_recycle; /* Close the connection when returning to pool */\r
+    proxy_worker *worker;   /* Connection pool this connection belogns to */\r
+    void         *data;     /* per scheme connection data */\r
+} proxy_conn_rec;\r
+\r
+typedef struct {\r
+        float cache_completion; /* completion percentage */\r
+        int content_length; /* length of the content */\r
+} proxy_completion;\r
+\r
+/* Connection pool */\r
+struct proxy_conn_pool {\r
+    apr_pool_t     *pool;   /* The pool used in constructor and destructor calls */\r
+    apr_sockaddr_t *addr;   /* Preparsed remote address info */\r
+#if APR_HAS_THREADS\r
+    apr_reslist_t  *res;    /* Connection resource list */\r
+#endif\r
+    proxy_conn_rec *conn;   /* Single connection for prefork mpm's */\r
+};\r
+\r
+/* woker status flags */\r
+#define PROXY_WORKER_INITIALIZED    0x0001\r
+#define PROXY_WORKER_IGNORE_ERRORS  0x0002\r
+#define PROXY_WORKER_IN_SHUTDOWN    0x0010\r
+#define PROXY_WORKER_DISABLED       0x0020\r
+#define PROXY_WORKER_IN_ERROR       0x0040\r
+\r
+#define PROXY_WORKER_IS_USABLE(f)   (!((f)->s->status & 0x00F0))\r
+\r
+/* default worker retry timeout in seconds */\r
+#define PROXY_WORKER_DEFAULT_RETRY  60\r
+#define PROXY_WORKER_MAX_ROUTE_SIZ  63\r
+\r
+/* Runtime worker status informations. Shared in scoreboard */\r
+typedef struct {\r
+    int             status;\r
+    apr_time_t      error_time; /* time of the last error */\r
+    int             retries;    /* number of retries on this worker */\r
+    int             lbstatus;   /* Current lbstatus */\r
+    int             lbfactor;   /* dynamic lbfactor */\r
+    apr_off_t       transfered; /* Number of bytes transfered to remote */\r
+    apr_off_t       readed;     /* Number of bytes readed from remote */\r
+    apr_size_t      elected;    /* Number of times the worker was elected */\r
+    char            route[PROXY_WORKER_MAX_ROUTE_SIZ+1];\r
+    char            redirect[PROXY_WORKER_MAX_ROUTE_SIZ+1];\r
+} proxy_worker_stat;\r
+\r
+/* Worker configuration */\r
+struct proxy_worker {\r
+    int             id;         /* scoreboard id */\r
+    apr_interval_time_t retry;  /* retry interval */\r
+    int             lbfactor;   /* initial load balancing factor */\r
+    const char      *name;\r
+    const char      *scheme;    /* scheme to use ajp|http|https */\r
+    const char      *hostname;  /* remote backend address */\r
+    const char      *route;     /* balancing route */\r
+    const char      *redirect;  /* temporary balancing redirection route */\r
+    apr_port_t      port;\r
+    int             min;        /* Desired minimum number of available connections */\r
+    int             smax;       /* Soft maximum on the total number of connections */\r
+    int             hmax;       /* Hard maximum on the total number of connections */\r
+    apr_interval_time_t ttl;    /* maximum amount of time in seconds a connection\r
+                                 * may be available while exceeding the soft limit */\r
+    apr_interval_time_t timeout; /* connection timeout */\r
+    char                timeout_set;\r
+    apr_interval_time_t acquire; /* acquire timeout when the maximum number of connections is exceeded */\r
+    char                acquire_set;\r
+    apr_size_t          recv_buffer_size;\r
+    char                recv_buffer_size_set;\r
+    apr_size_t          io_buffer_size;\r
+    char                io_buffer_size_set;\r
+    char                keepalive;\r
+    char                keepalive_set;\r
+    proxy_conn_pool     *cp;        /* Connection pool to use */\r
+    proxy_worker_stat   *s;         /* Shared data */\r
+    void                *opaque;    /* per scheme worker data */\r
+};\r
+\r
+struct proxy_balancer {\r
+    apr_array_header_t *workers; /* array of proxy_workers */\r
+    const char *name;            /* name of the load balancer */\r
+    const char *sticky;          /* sticky session identifier */\r
+    int         sticky_force;    /* Disable failover for sticky sessions */\r
+    apr_interval_time_t timeout; /* Timeout for waiting on free connection */\r
+    int                 max_attempts; /* Number of attempts before failing */\r
+    char                max_attempts_set;\r
+\r
+    /* XXX: Perhaps we will need the proc mutex too.\r
+     * Altrough we are only using arithmetic operations\r
+     * it may lead to a incorrect calculations.\r
+     * For now use only the thread mutex.\r
+     */\r
+#if APR_HAS_THREADS\r
+    apr_thread_mutex_t  *mutex;  /* Thread lock for updating lb params */\r
+#endif\r
+};\r
+\r
+/* hooks */\r
+\r
+/* Create a set of PROXY_DECLARE(type), PROXY_DECLARE_NONSTD(type) and \r
+ * PROXY_DECLARE_DATA with appropriate export and import tags for the platform\r
+ */\r
+#if !defined(WIN32)\r
+#define PROXY_DECLARE(type)            type\r
+#define PROXY_DECLARE_NONSTD(type)     type\r
+#define PROXY_DECLARE_DATA\r
+#elif defined(PROXY_DECLARE_STATIC)\r
+#define PROXY_DECLARE(type)            type __stdcall\r
+#define PROXY_DECLARE_NONSTD(type)     type\r
+#define PROXY_DECLARE_DATA\r
+#elif defined(PROXY_DECLARE_EXPORT)\r
+#define PROXY_DECLARE(type)            __declspec(dllexport) type __stdcall\r
+#define PROXY_DECLARE_NONSTD(type)     __declspec(dllexport) type\r
+#define PROXY_DECLARE_DATA             __declspec(dllexport)\r
+#else\r
+#define PROXY_DECLARE(type)            __declspec(dllimport) type __stdcall\r
+#define PROXY_DECLARE_NONSTD(type)     __declspec(dllimport) type\r
+#define PROXY_DECLARE_DATA             __declspec(dllimport)\r
+#endif\r
+\r
+/**\r
+ * Hook an optional proxy hook.  Unlike static hooks, this uses a macro\r
+ * instead of a function.\r
+ */\r
+#define PROXY_OPTIONAL_HOOK(name,fn,pre,succ,order) \\r
+        APR_OPTIONAL_HOOK(proxy,name,fn,pre,succ,order)\r
+\r
+APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, scheme_handler, (request_rec *r, \r
+                          proxy_worker *worker, proxy_server_conf *conf, char *url, \r
+                          const char *proxyhost, apr_port_t proxyport))\r
+APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, canon_handler, (request_rec *r, \r
+                          char *url))\r
+\r
+APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, create_req, (request_rec *r, request_rec *pr))\r
+APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, fixups, (request_rec *r)) \r
+\r
+/**\r
+ * pre request hook.\r
+ * It will return the most suitable worker at the moment\r
+ * and coresponding balancer.\r
+ * The url is rewritten from balancer://cluster/uri to scheme://host:port/uri\r
+ * and then the scheme_handler is called.\r
+ *\r
+ */\r
+APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, pre_request, (proxy_worker **worker,\r
+                          proxy_balancer **balancer,\r
+                          request_rec *r,\r
+                          proxy_server_conf *conf, char **url))                          \r
+/**\r
+ * post request hook.\r
+ * It is called after request for updating runtime balancer status.\r
+ */\r
+APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, post_request, (proxy_worker *worker,\r
+                          proxy_balancer *balancer, request_rec *r,\r
+                          proxy_server_conf *conf))\r
+\r
+\r
+/* proxy_util.c */\r
+\r
+PROXY_DECLARE(request_rec *)ap_proxy_make_fake_req(conn_rec *c, request_rec *r);\r
+PROXY_DECLARE(int) ap_proxy_hex2c(const char *x);\r
+PROXY_DECLARE(void) ap_proxy_c2hex(int ch, char *x);\r
+PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, enum enctype t,\r
+                                       int isenc);\r
+PROXY_DECLARE(char *)ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp,\r
+                                           char **passwordp, char **hostp, apr_port_t *port);\r
+PROXY_DECLARE(const char *)ap_proxy_date_canon(apr_pool_t *p, const char *x);\r
+PROXY_DECLARE(int) ap_proxy_liststr(const char *list, const char *val);\r
+PROXY_DECLARE(char *)ap_proxy_removestr(apr_pool_t *pool, const char *list, const char *val);\r
+PROXY_DECLARE(int) ap_proxy_hex2sec(const char *x);\r
+PROXY_DECLARE(void) ap_proxy_sec2hex(int t, char *y);\r
+PROXY_DECLARE(int) ap_proxyerror(request_rec *r, int statuscode, const char *message);\r
+PROXY_DECLARE(int) ap_proxy_is_ipaddr(struct dirconn_entry *This, apr_pool_t *p);\r
+PROXY_DECLARE(int) ap_proxy_is_domainname(struct dirconn_entry *This, apr_pool_t *p);\r
+PROXY_DECLARE(int) ap_proxy_is_hostname(struct dirconn_entry *This, apr_pool_t *p);\r
+PROXY_DECLARE(int) ap_proxy_is_word(struct dirconn_entry *This, apr_pool_t *p);\r
+PROXY_DECLARE(int) ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf, apr_sockaddr_t *uri_addr);\r
+PROXY_DECLARE(int) ap_proxy_pre_http_request(conn_rec *c, request_rec *r);\r
+PROXY_DECLARE(apr_status_t) ap_proxy_string_read(conn_rec *c, apr_bucket_brigade *bb, char *buff, size_t bufflen, int *eos);\r
+PROXY_DECLARE(void) ap_proxy_table_unmerge(apr_pool_t *p, apr_table_t *t, char *key);\r
+/* DEPRECATED (will be replaced with ap_proxy_connect_backend */\r
+PROXY_DECLARE(int) ap_proxy_connect_to_backend(apr_socket_t **, const char *, apr_sockaddr_t *, const char *, proxy_server_conf *, server_rec *, apr_pool_t *);\r
+PROXY_DECLARE(int) ap_proxy_ssl_enable(conn_rec *c);\r
+PROXY_DECLARE(int) ap_proxy_ssl_disable(conn_rec *c);\r
+\r
+/* Connection pool API */\r
+/**\r
+ * Get the worker from proxy configuration\r
+ * @param p     memory pool used for finding worker\r
+ * @param conf  current proxy server configuration\r
+ * @param url   url to find the worker from\r
+ * @return      proxy_worker or NULL if not found\r
+ */\r
+PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,\r
+                                                  proxy_server_conf *conf,\r
+                                                  const char *url);\r
+/**\r
+ * Add the worker to proxy configuration\r
+ * @param worker the new worker\r
+ * @param p      memory pool to allocate worker from \r
+ * @param conf   current proxy server configuration\r
+ * @param url    url containing worker name\r
+ * @return       error message or NULL if successfull\r
+ */\r
+PROXY_DECLARE(const char *) ap_proxy_add_worker(proxy_worker **worker,\r
+                                                apr_pool_t *p,\r
+                                                proxy_server_conf *conf,\r
+                                                const char *url);\r
+\r
+/**\r
+ * Create new worker\r
+ * @param p      memory pool to allocate worker from \r
+ * @return       new worker\r
+ */\r
+PROXY_DECLARE(proxy_worker *) ap_proxy_create_worker(apr_pool_t *p);\r
+\r
+/**\r
+ * Initize the worker's shared data\r
+ * @param conf   current proxy server configuration\r
+ * @param s      current server record\r
+ * @param worker worker to initialize\r
+ */\r
+PROXY_DECLARE(void) ap_proxy_initialize_worker_share(proxy_server_conf *conf,\r
+                                                     proxy_worker *worker);\r
+\r
+\r
+/**\r
+ * Initize the worker\r
+ * @param worker worker to initialize\r
+ * @param p      memory pool to allocate worker from \r
+ * @param s      current server record\r
+ * @return       APR_SUCCESS or error code\r
+ */\r
+PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker,\r
+                                                       server_rec *s);\r
+/**\r
+ * Get the balancer from proxy configuration\r
+ * @param p     memory pool used for finding balancer\r
+ * @param conf  current proxy server configuration\r
+ * @param url   url to find the worker from. Has to have balancer:// prefix\r
+ * @return      proxy_balancer or NULL if not found\r
+ */\r
+PROXY_DECLARE(proxy_balancer *) ap_proxy_get_balancer(apr_pool_t *p,\r
+                                                      proxy_server_conf *conf,\r
+                                                      const char *url);\r
+/**\r
+ * Add the balancer to proxy configuration\r
+ * @param balancer the new balancer\r
+ * @param p      memory pool to allocate balancer from \r
+ * @param conf   current proxy server configuration\r
+ * @param url    url containing balancer name\r
+ * @return       error message or NULL if successfull\r
+ */\r
+PROXY_DECLARE(const char *) ap_proxy_add_balancer(proxy_balancer **balancer,\r
+                                                  apr_pool_t *p,\r
+                                                  proxy_server_conf *conf,\r
+                                                  const char *url);\r
+\r
+/**\r
+ * Add the worker to the balancer\r
+ * @param pool     memory pool for adding worker \r
+ * @param balancer balancer to add to\r
+ * @param balancer worker to add\r
+ * @note Single worker can be added to multiple balancers.\r
+ */\r
+PROXY_DECLARE(void) ap_proxy_add_worker_to_balancer(apr_pool_t *pool,\r
+                                                    proxy_balancer *balancer,\r
+                                                    proxy_worker *worker);\r
+/**\r
+ * Get the most suitable worker and(or) balancer for the request\r
+ * @param worker   worker used for processing request\r
+ * @param balancer balancer used for processing request\r
+ * @param r        current request\r
+ * @param conf     current proxy server configuration\r
+ * @param url      request url that balancer can rewrite.\r
+ * @return         OK or  HTTP_XXX error \r
+ * @note It calls balancer pre_request hook if the url starts with balancer://\r
+ * The balancer then rewrites the url to particular worker, like http://host:port\r
+ */\r
+PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,\r
+                                        proxy_balancer **balancer,\r
+                                        request_rec *r,\r
+                                        proxy_server_conf *conf,\r
+                                        char **url);\r
+/**\r
+ * Post request worker and balancer cleanup\r
+ * @param worker   worker used for processing request\r
+ * @param balancer balancer used for processing request\r
+ * @param r        current request\r
+ * @param conf     current proxy server configuration\r
+ * @return         OK or  HTTP_XXX error\r
+ * @note When ever the pre_request is called, the post_request has to be\r
+ * called too. \r
+ */\r
+PROXY_DECLARE(int) ap_proxy_post_request(proxy_worker *worker,\r
+                                         proxy_balancer *balancer,\r
+                                         request_rec *r,\r
+                                         proxy_server_conf *conf);\r
+/**\r
+ * Deternime backend hostname and port\r
+ * @param p       memory pool used for processing\r
+ * @param r       current request\r
+ * @param conf    current proxy server configuration\r
+ * @param worker  worker used for processing request\r
+ * @param conn    proxy connection struct\r
+ * @param uri     processed uri\r
+ * @param url     request url\r
+ * @param proxyname are we connecting directly or via s proxy\r
+ * @param proxyport proxy host port\r
+ * @param server_portstr Via headers server port\r
+ * @param server_portstr_size size of the server_portstr buffer\r
+ * @return         OK or HTTP_XXX error\r
+ */                                         \r
+PROXY_DECLARE(int) ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,\r
+                                                 proxy_server_conf *conf,\r
+                                                 proxy_worker *worker,\r
+                                                 proxy_conn_rec *conn,\r
+                                                 apr_uri_t *uri,\r
+                                                 char **url,\r
+                                                 const char *proxyname,\r
+                                                 apr_port_t proxyport,\r
+                                                 char *server_portstr,\r
+                                                 int server_portstr_size);\r
+/**\r
+ * Mark a worker for retry\r
+ * @param proxy_function calling proxy scheme (http, ajp, ...)\r
+ * @param conf    current proxy server configuration\r
+ * @param worker  worker used for retrying\r
+ * @param s       current server record\r
+ * @return        OK if marked for retry, DECLINED otherwise\r
+ * @note Worker will be marker for retry if the time of the last retry\r
+ * has been ellapsed. In case there is no retry option set, defaults to\r
+ * number_of_retries seconds.\r
+ */                                         \r
+PROXY_DECLARE(int) ap_proxy_retry_worker(const char *proxy_function,\r
+                                         proxy_worker *worker,\r
+                                         server_rec *s);\r
+/**\r
+ * Acquire a connection from workers connection pool\r
+ * @param proxy_function calling proxy scheme (http, ajp, ...)\r
+ * @param conn    acquired connection\r
+ * @param worker  worker used for obtaining connection\r
+ * @param s       current server record\r
+ * @return        OK or HTTP_XXX error\r
+ * @note If the number of connections is exhaused the function will\r
+ * block untill the timeout is reached.\r
+ */                                         \r
+PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function,\r
+                                               proxy_conn_rec **conn,\r
+                                               proxy_worker *worker,\r
+                                               server_rec *s);\r
+/**\r
+ * Release a connection back to worker connection pool\r
+ * @param proxy_function calling proxy scheme (http, ajp, ...)\r
+ * @param conn    acquired connection\r
+ * @param s       current server record\r
+ * @return        OK or HTTP_XXX error\r
+ * @note The connection will be closed if conn->close_on_release is set\r
+ */                                         \r
+PROXY_DECLARE(int) ap_proxy_release_connection(const char *proxy_function,\r
+                                               proxy_conn_rec *conn,\r
+                                               server_rec *s);\r
+/**\r
+ * Make a connection to the backend\r
+ * @param proxy_function calling proxy scheme (http, ajp, ...)\r
+ * @param conn    acquired connection\r
+ * @param worker  connection worker\r
+ * @param s       current server record\r
+ * @return        OK or HTTP_XXX error\r
+ * @note In case the socket already exists for conn, just check the link\r
+ * status.\r
+ */                                         \r
+PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,\r
+                                            proxy_conn_rec *conn,\r
+                                            proxy_worker *worker,\r
+                                            server_rec *s);\r
+/**\r
+ * Make a connection record for backend connection\r
+ * @param proxy_function calling proxy scheme (http, ajp, ...)\r
+ * @param conn    acquired connection\r
+ * @param c       client connection record\r
+ * @param s       current server record\r
+ * @return        OK or HTTP_XXX error\r
+ */                                         \r
+PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function,\r
+                                              proxy_conn_rec *conn,\r
+                                              conn_rec *c, server_rec *s);\r
+\r
+/* Scoreboard */\r
+#if MODULE_MAGIC_NUMBER_MAJOR > 20020903\r
+#define PROXY_HAS_SCOREBOARD 1\r
+#else\r
+#define PROXY_HAS_SCOREBOARD 0\r
+#endif\r
+\r
+/* The number of dynamic workers that can be added when reconfiguring.\r
+ * If this limit is reached you must stop and restart the server.\r
+ */\r
+#define PROXY_DYNAMIC_BALANCER_LIMIT    16\r
+/**\r
+ * Calculate number of maximum number of workers in scoreboard.\r
+ * @return     number of workers to allocate in the scoreboard\r
+ */\r
+int ap_proxy_lb_workers(void);\r
+\r
+/* For proxy_util */\r
+extern module PROXY_DECLARE_DATA proxy_module;\r
+\r
+extern int PROXY_DECLARE_DATA proxy_lb_workers;\r
+\r
+#endif /*MOD_PROXY_H*/\r
index 73540d24548a1a2e511ad43d61634ae2e75ecb32..1f38a0487c0668b7c5463c3c144834c1cd75b5f1 100644 (file)
@@ -35,7 +35,7 @@ module AP_MODULE_DECLARE_DATA proxy_balancer_module;
 #define PROXY_BALANCER_UNLOCK(b)    APR_SUCCESS
 #endif
 
-static int init_runtime_score(proxy_server_conf *conf, proxy_balancer *balancer)
+static int init_runtime_score(proxy_server_conf *conf, server_rec *s, proxy_balancer *balancer)
 {
     int i;
     int median, ffactor = 0;
@@ -45,6 +45,7 @@ static int init_runtime_score(proxy_server_conf *conf, proxy_balancer *balancer)
 
     for (i = 0; i < balancer->workers->nelts; i++) {
         ap_proxy_initialize_worker_share(conf, workers);
+       ap_proxy_initialize_worker(workers, s);
         workers->s->status = PROXY_WORKER_INITIALIZED; 
         ++workers;
     }
@@ -441,7 +442,7 @@ static int proxy_balancer_pre_request(proxy_worker **worker,
         apr_table_setn(r->notes, "session-route", route);
     }
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                 "proxy: BALANCER (%s) worker (%s) rewrritten to %s",
+                 "proxy: BALANCER (%s) worker (%s) rewritten to %s",
                  (*balancer)->name, (*worker)->name, *url);
 
     return access_status;
@@ -786,7 +787,7 @@ static void child_init(apr_pool_t *p, server_rec *s)
         /* Initialize shared scoreboard data */ 
         balancer = (proxy_balancer *)conf->balancers->elts;
         for (i = 0; i < conf->balancers->nelts; i++) {
-            init_runtime_score(conf, balancer);
+           init_runtime_score(conf, s, balancer);
             balancer++;
         }
         s = s->next;
index b82c9796029c26fc754ac2f4d86f9558bcee7c32..2819ca800178825d5656aa284bbd0f414e180961 100644 (file)
-/* Copyright 1999-2004 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Utility routines for Apache proxy */
-#include "mod_proxy.h"
-#include "ap_mpm.h"
-#include "scoreboard.h"
-#include "apr_version.h"
-
-#if APR_HAVE_UNISTD_H
-#include <unistd.h>         /* for getpid() */
-#endif
-
-#if (APR_MAJOR_VERSION < 1)
-#undef apr_socket_create
-#define apr_socket_create apr_socket_create_ex
-#endif
-
-/* Global balancer counter */
-static int lb_workers = 0;
-static int lb_workers_limit = 0;
-
-static int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r);
-static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r);
-static int proxy_match_hostname(struct dirconn_entry *This, request_rec *r);
-static int proxy_match_word(struct dirconn_entry *This, request_rec *r);
-
-APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, create_req, 
-                                   (request_rec *r, request_rec *pr), (r, pr),
-                                   OK, DECLINED)
-
-/* already called in the knowledge that the characters are hex digits */
-PROXY_DECLARE(int) ap_proxy_hex2c(const char *x)
-{
-    int i, ch;
-
-#if !APR_CHARSET_EBCDIC
-    ch = x[0];
-    if (apr_isdigit(ch))
-       i = ch - '0';
-    else if (apr_isupper(ch))
-       i = ch - ('A' - 10);
-    else
-       i = ch - ('a' - 10);
-    i <<= 4;
-
-    ch = x[1];
-    if (apr_isdigit(ch))
-       i += ch - '0';
-    else if (apr_isupper(ch))
-       i += ch - ('A' - 10);
-    else
-       i += ch - ('a' - 10);
-    return i;
-#else /*APR_CHARSET_EBCDIC*/
-    /* we assume that the hex value refers to an ASCII character
-     * so convert to EBCDIC so that it makes sense locally;
-     *
-     * example:
-     *
-     * client specifies %20 in URL to refer to a space char;
-     * at this point we're called with EBCDIC "20"; after turning
-     * EBCDIC "20" into binary 0x20, we then need to assume that 0x20
-     * represents an ASCII char and convert 0x20 to EBCDIC, yielding
-     * 0x40
-     */
-    char buf[1];
-
-    if (1 == sscanf(x, "%2x", &i)) {
-        buf[0] = i & 0xFF;
-        ap_xlate_proto_from_ascii(buf, 1);
-        return buf[0];
-    }
-    else {
-        return 0;
-    }
-#endif /*APR_CHARSET_EBCDIC*/
-}
-
-PROXY_DECLARE(void) ap_proxy_c2hex(int ch, char *x)
-{
-#if !APR_CHARSET_EBCDIC
-    int i;
-
-    x[0] = '%';
-    i = (ch & 0xF0) >> 4;
-    if (i >= 10)
-       x[1] = ('A' - 10) + i;
-    else
-       x[1] = '0' + i;
-
-    i = ch & 0x0F;
-    if (i >= 10)
-       x[2] = ('A' - 10) + i;
-    else
-       x[2] = '0' + i;
-#else /*APR_CHARSET_EBCDIC*/
-    static const char ntoa[] = { "0123456789ABCDEF" };
-    char buf[1];
-
-    ch &= 0xFF;
-
-    buf[0] = ch;
-    ap_xlate_proto_to_ascii(buf, 1);
-
-    x[0] = '%';
-    x[1] = ntoa[(buf[0] >> 4) & 0x0F];
-    x[2] = ntoa[buf[0] & 0x0F];
-    x[3] = '\0';
-#endif /*APR_CHARSET_EBCDIC*/
-}
-
-/*
- * canonicalise a URL-encoded string
- */
-
-/*
- * Convert a URL-encoded string to canonical form.
- * It decodes characters which need not be encoded,
- * and encodes those which must be encoded, and does not touch
- * those which must not be touched.
- */
-PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, enum enctype t,
-       int isenc)
-{
-    int i, j, ch;
-    char *y;
-    char *allowed;     /* characters which should not be encoded */
-    char *reserved;    /* characters which much not be en/de-coded */
-
-/* N.B. in addition to :@&=, this allows ';' in an http path
- * and '?' in an ftp path -- this may be revised
- * 
- * Also, it makes a '+' character in a search string reserved, as
- * it may be form-encoded. (Although RFC 1738 doesn't allow this -
- * it only permits ; / ? : @ = & as reserved chars.)
- */
-    if (t == enc_path)
-       allowed = "$-_.+!*'(),;:@&=";
-    else if (t == enc_search)
-       allowed = "$-_.!*'(),;:@&=";
-    else if (t == enc_user)
-       allowed = "$-_.+!*'(),;@&=";
-    else if (t == enc_fpath)
-       allowed = "$-_.+!*'(),?:@&=";
-    else                       /* if (t == enc_parm) */
-       allowed = "$-_.+!*'(),?/:@&=";
-
-    if (t == enc_path)
-       reserved = "/";
-    else if (t == enc_search)
-       reserved = "+";
-    else
-       reserved = "";
-
-    y = apr_palloc(p, 3 * len + 1);
-
-    for (i = 0, j = 0; i < len; i++, j++) {
-/* always handle '/' first */
-       ch = x[i];
-       if (strchr(reserved, ch)) {
-           y[j] = ch;
-           continue;
-       }
-/* decode it if not already done */
-       if (isenc && ch == '%') {
-           if (!apr_isxdigit(x[i + 1]) || !apr_isxdigit(x[i + 2]))
-               return NULL;
-           ch = ap_proxy_hex2c(&x[i + 1]);
-           i += 2;
-           if (ch != 0 && strchr(reserved, ch)) {      /* keep it encoded */
-               ap_proxy_c2hex(ch, &y[j]);
-               j += 2;
-               continue;
-           }
-       }
-/* recode it, if necessary */
-       if (!apr_isalnum(ch) && !strchr(allowed, ch)) {
-           ap_proxy_c2hex(ch, &y[j]);
-           j += 2;
-       }
-       else
-           y[j] = ch;
-    }
-    y[j] = '\0';
-    return y;
-}
-
-/*
- * Parses network-location.
- *    urlp           on input the URL; on output the path, after the leading /
- *    user           NULL if no user/password permitted
- *    password       holder for password
- *    host           holder for host
- *    port           port number; only set if one is supplied.
- *
- * Returns an error string.
- */
-PROXY_DECLARE(char *)
-     ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp,
-                       char **passwordp, char **hostp, apr_port_t *port)
-{
-    char *addr, *scope_id, *strp, *host, *url = *urlp;
-    char *user = NULL, *password = NULL;
-    apr_port_t tmp_port;
-    apr_status_t rv;
-
-    if (url[0] != '/' || url[1] != '/')
-       return "Malformed URL";
-    host = url + 2;
-    url = strchr(host, '/');
-    if (url == NULL)
-       url = "";
-    else
-       *(url++) = '\0';        /* skip seperating '/' */
-
-    /* find _last_ '@' since it might occur in user/password part */
-    strp = strrchr(host, '@');
-
-    if (strp != NULL) {
-       *strp = '\0';
-       user = host;
-       host = strp + 1;
-
-/* find password */
-       strp = strchr(user, ':');
-       if (strp != NULL) {
-           *strp = '\0';
-           password = ap_proxy_canonenc(p, strp + 1, strlen(strp + 1), enc_user, 1);
-           if (password == NULL)
-               return "Bad %-escape in URL (password)";
-       }
-
-       user = ap_proxy_canonenc(p, user, strlen(user), enc_user, 1);
-       if (user == NULL)
-           return "Bad %-escape in URL (username)";
-    }
-    if (userp != NULL) {
-       *userp = user;
-    }
-    if (passwordp != NULL) {
-       *passwordp = password;
-    }
-
-    /* Parse the host string to separate host portion from optional port.
-     * Perform range checking on port.
-     */
-    rv = apr_parse_addr_port(&addr, &scope_id, &tmp_port, host, p);
-    if (rv != APR_SUCCESS || addr == NULL || scope_id != NULL) {
-        return "Invalid host/port";
-    }
-    if (tmp_port != 0) { /* only update caller's port if port was specified */
-        *port = tmp_port;
-    }
-
-    ap_str_tolower(addr); /* DNS names are case-insensitive */
-
-    *urlp = url;
-    *hostp = addr;
-
-    return NULL;
-}
-
-static const char * const lwday[7] =
-{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
-
-/*
- * If the date is a valid RFC 850 date or asctime() date, then it
- * is converted to the RFC 1123 format, otherwise it is not modified.
- * This routine is not very fast at doing conversions, as it uses
- * sscanf and sprintf. However, if the date is already correctly
- * formatted, then it exits very quickly.
- */
-PROXY_DECLARE(const char *)
-     ap_proxy_date_canon(apr_pool_t *p, const char *x1)
-{
-    char *x = apr_pstrdup(p, x1);
-    int wk, mday, year, hour, min, sec, mon;
-    char *q, month[4], zone[4], week[4];
-
-    q = strchr(x, ',');
-    /* check for RFC 850 date */
-    if (q != NULL && q - x > 3 && q[1] == ' ') {
-       *q = '\0';
-       for (wk = 0; wk < 7; wk++)
-           if (strcmp(x, lwday[wk]) == 0)
-               break;
-       *q = ',';
-       if (wk == 7)
-           return x;           /* not a valid date */
-       if (q[4] != '-' || q[8] != '-' || q[11] != ' ' || q[14] != ':' ||
-           q[17] != ':' || strcmp(&q[20], " GMT") != 0)
-           return x;
-       if (sscanf(q + 2, "%u-%3s-%u %u:%u:%u %3s", &mday, month, &year,
-                  &hour, &min, &sec, zone) != 7)
-           return x;
-       if (year < 70)
-           year += 2000;
-       else
-           year += 1900;
-    }
-    else {
-/* check for acstime() date */
-       if (x[3] != ' ' || x[7] != ' ' || x[10] != ' ' || x[13] != ':' ||
-           x[16] != ':' || x[19] != ' ' || x[24] != '\0')
-           return x;
-       if (sscanf(x, "%3s %3s %u %u:%u:%u %u", week, month, &mday, &hour,
-                  &min, &sec, &year) != 7)
-           return x;
-       for (wk = 0; wk < 7; wk++)
-           if (strcmp(week, apr_day_snames[wk]) == 0)
-               break;
-       if (wk == 7)
-           return x;
-    }
-
-/* check date */
-    for (mon = 0; mon < 12; mon++)
-       if (strcmp(month, apr_month_snames[mon]) == 0)
-           break;
-    if (mon == 12)
-       return x;
-
-    q = apr_palloc(p, 30);
-    apr_snprintf(q, 30, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", apr_day_snames[wk],
-       mday, apr_month_snames[mon], year, hour, min, sec);
-    return q;
-}
-
-PROXY_DECLARE(request_rec *)ap_proxy_make_fake_req(conn_rec *c, request_rec *r)
-{
-    request_rec *rp = apr_pcalloc(c->pool, sizeof(*r));
-
-    rp->pool            = c->pool;
-    rp->status          = HTTP_OK;
-
-    rp->headers_in      = apr_table_make(c->pool, 50);
-    rp->subprocess_env  = apr_table_make(c->pool, 50);
-    rp->headers_out     = apr_table_make(c->pool, 12);
-    rp->err_headers_out = apr_table_make(c->pool, 5);
-    rp->notes           = apr_table_make(c->pool, 5);
-
-    rp->server = r->server;
-    rp->proxyreq = r->proxyreq;
-    rp->request_time = r->request_time;
-    rp->connection      = c;
-    rp->output_filters  = c->output_filters;
-    rp->input_filters   = c->input_filters;
-    rp->proto_output_filters  = c->output_filters;
-    rp->proto_input_filters   = c->input_filters;
-
-    rp->request_config  = ap_create_request_config(c->pool);
-    proxy_run_create_req(r, rp);
-
-    return rp;
-}
-
-
-/*
- * list is a comma-separated list of case-insensitive tokens, with
- * optional whitespace around the tokens.
- * The return returns 1 if the token val is found in the list, or 0
- * otherwise.
- */
-PROXY_DECLARE(int) ap_proxy_liststr(const char *list, const char *val)
-{
-    int len, i;
-    const char *p;
-
-    len = strlen(val);
-
-    while (list != NULL) {
-       p = ap_strchr_c(list, ',');
-       if (p != NULL) {
-           i = p - list;
-           do
-               p++;
-           while (apr_isspace(*p));
-       }
-       else
-           i = strlen(list);
-
-       while (i > 0 && apr_isspace(list[i - 1]))
-           i--;
-       if (i == len && strncasecmp(list, val, len) == 0)
-           return 1;
-       list = p;
-    }
-    return 0;
-}
-
-/*
- * list is a comma-separated list of case-insensitive tokens, with
- * optional whitespace around the tokens.
- * if val appears on the list of tokens, it is removed from the list,
- * and the new list is returned.
- */
-PROXY_DECLARE(char *)ap_proxy_removestr(apr_pool_t *pool, const char *list, const char *val)
-{
-    int len, i;
-    const char *p;
-    char *new = NULL;
-
-    len = strlen(val);
-
-    while (list != NULL) {
-       p = ap_strchr_c(list, ',');
-       if (p != NULL) {
-           i = p - list;
-           do
-               p++;
-           while (apr_isspace(*p));
-       }
-       else
-           i = strlen(list);
-
-       while (i > 0 && apr_isspace(list[i - 1]))
-           i--;
-       if (i == len && strncasecmp(list, val, len) == 0) {
-           /* do nothing */
-       }
-       else {
-           if (new)
-               new = apr_pstrcat(pool, new, ",", apr_pstrndup(pool, list, i), NULL);
-           else
-               new = apr_pstrndup(pool, list, i);
-       }
-       list = p;
-    }
-    return new;
-}
-
-/*
- * Converts 8 hex digits to a time integer
- */
-PROXY_DECLARE(int) ap_proxy_hex2sec(const char *x)
-{
-    int i, ch;
-    unsigned int j;
-
-    for (i = 0, j = 0; i < 8; i++) {
-       ch = x[i];
-       j <<= 4;
-       if (apr_isdigit(ch))
-           j |= ch - '0';
-       else if (apr_isupper(ch))
-           j |= ch - ('A' - 10);
-       else
-           j |= ch - ('a' - 10);
-    }
-    if (j == 0xffffffff)
-       return -1;              /* so that it works with 8-byte ints */
-    else
-       return j;
-}
-
-/*
- * Converts a time integer to 8 hex digits
- */
-PROXY_DECLARE(void) ap_proxy_sec2hex(int t, char *y)
-{
-    int i, ch;
-    unsigned int j = t;
-
-    for (i = 7; i >= 0; i--) {
-       ch = j & 0xF;
-       j >>= 4;
-       if (ch >= 10)
-           y[i] = ch + ('A' - 10);
-       else
-           y[i] = ch + '0';
-    }
-    y[8] = '\0';
-}
-
-PROXY_DECLARE(int) ap_proxyerror(request_rec *r, int statuscode, const char *message)
-{
-    apr_table_setn(r->notes, "error-notes",
-       apr_pstrcat(r->pool, 
-               "The proxy server could not handle the request "
-               "<em><a href=\"", ap_escape_uri(r->pool, r->uri),
-               "\">", ap_escape_html(r->pool, r->method),
-               "&nbsp;", 
-               ap_escape_html(r->pool, r->uri), "</a></em>.<p>\n"
-               "Reason: <strong>",
-               ap_escape_html(r->pool, message), 
-               "</strong></p>", NULL));
-
-    /* Allow "error-notes" string to be printed by ap_send_error_response() */
-    apr_table_setn(r->notes, "verbose-error-to", apr_pstrdup(r->pool, "*"));
-
-    r->status_line = apr_psprintf(r->pool, "%3.3u Proxy Error", statuscode);
-    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                        "proxy: %s returned by %s", message, r->uri);
-    return statuscode;
-}
-
-static const char *
-     proxy_get_host_of_request(request_rec *r)
-{
-    char *url, *user = NULL, *password = NULL, *err, *host;
-    apr_port_t port;
-
-    if (r->hostname != NULL)
-       return r->hostname;
-
-    /* Set url to the first char after "scheme://" */
-    if ((url = strchr(r->uri, ':')) == NULL
-       || url[1] != '/' || url[2] != '/')
-       return NULL;
-
-    url = apr_pstrdup(r->pool, &url[1]);       /* make it point to "//", which is what proxy_canon_netloc expects */
-
-    err = ap_proxy_canon_netloc(r->pool, &url, &user, &password, &host, &port);
-
-    if (err != NULL)
-       ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                    "%s", err);
-
-    r->hostname = host;
-
-    return host;               /* ought to return the port, too */
-}
-
-/* Return TRUE if addr represents an IP address (or an IP network address) */
-PROXY_DECLARE(int) ap_proxy_is_ipaddr(struct dirconn_entry *This, apr_pool_t *p)
-{
-    const char *addr = This->name;
-    long ip_addr[4];
-    int i, quads;
-    long bits;
-
-    /* if the address is given with an explicit netmask, use that */
-    /* Due to a deficiency in apr_inet_addr(), it is impossible to parse */
-    /* "partial" addresses (with less than 4 quads) correctly, i.e.  */
-    /* 192.168.123 is parsed as 192.168.0.123, which is not what I want. */
-    /* I therefore have to parse the IP address manually: */
-    /*if (proxy_readmask(This->name, &This->addr.s_addr, &This->mask.s_addr) == 0) */
-    /* addr and mask were set by proxy_readmask() */
-    /*return 1; */
-
-    /* Parse IP addr manually, optionally allowing */
-    /* abbreviated net addresses like 192.168. */
-
-    /* Iterate over up to 4 (dotted) quads. */
-    for (quads = 0; quads < 4 && *addr != '\0'; ++quads) {
-       char *tmp;
-
-       if (*addr == '/' && quads > 0)  /* netmask starts here. */
-           break;
-
-       if (!apr_isdigit(*addr))
-           return 0;           /* no digit at start of quad */
-
-       ip_addr[quads] = strtol(addr, &tmp, 0);
-
-       if (tmp == addr)        /* expected a digit, found something else */
-           return 0;
-
-       if (ip_addr[quads] < 0 || ip_addr[quads] > 255) {
-           /* invalid octet */
-           return 0;
-       }
-
-       addr = tmp;
-
-       if (*addr == '.' && quads != 3)
-           ++addr;             /* after the 4th quad, a dot would be illegal */
-    }
-
-    for (This->addr.s_addr = 0, i = 0; i < quads; ++i)
-       This->addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
-
-    if (addr[0] == '/' && apr_isdigit(addr[1])) {      /* net mask follows: */
-       char *tmp;
-
-       ++addr;
-
-       bits = strtol(addr, &tmp, 0);
-
-       if (tmp == addr)        /* expected a digit, found something else */
-           return 0;
-
-       addr = tmp;
-
-       if (bits < 0 || bits > 32)      /* netmask must be between 0 and 32 */
-           return 0;
-
-    }
-    else {
-       /* Determine (i.e., "guess") netmask by counting the */
-       /* number of trailing .0's; reduce #quads appropriately */
-       /* (so that 192.168.0.0 is equivalent to 192.168.)        */
-       while (quads > 0 && ip_addr[quads - 1] == 0)
-           --quads;
-
-       /* "IP Address should be given in dotted-quad form, optionally followed by a netmask (e.g., 192.168.111.0/24)"; */
-       if (quads < 1)
-           return 0;
-
-       /* every zero-byte counts as 8 zero-bits */
-       bits = 8 * quads;
-
-       if (bits != 32)         /* no warning for fully qualified IP address */
-            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
-             "Warning: NetMask not supplied with IP-Addr; guessing: %s/%ld\n",
-                inet_ntoa(This->addr), bits);
-    }
-
-    This->mask.s_addr = htonl(APR_INADDR_NONE << (32 - bits));
-
-    if (*addr == '\0' && (This->addr.s_addr & ~This->mask.s_addr) != 0) {
-        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
-           "Warning: NetMask and IP-Addr disagree in %s/%ld\n",
-               inet_ntoa(This->addr), bits);
-       This->addr.s_addr &= This->mask.s_addr;
-        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
-           "         Set to %s/%ld\n",
-               inet_ntoa(This->addr), bits);
-    }
-
-    if (*addr == '\0') {
-       This->matcher = proxy_match_ipaddr;
-       return 1;
-    }
-    else
-       return (*addr == '\0'); /* okay iff we've parsed the whole string */
-}
-
-/* Return TRUE if addr represents an IP address (or an IP network address) */
-static int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r)
-{
-    int i, ip_addr[4];
-    struct in_addr addr, *ip;
-    const char *host = proxy_get_host_of_request(r);
-
-    if (host == NULL)   /* oops! */
-       return 0;
-
-    memset(&addr, '\0', sizeof addr);
-    memset(ip_addr, '\0', sizeof ip_addr);
-
-    if (4 == sscanf(host, "%d.%d.%d.%d", &ip_addr[0], &ip_addr[1], &ip_addr[2], &ip_addr[3])) {
-       for (addr.s_addr = 0, i = 0; i < 4; ++i)
-           addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
-
-       if (This->addr.s_addr == (addr.s_addr & This->mask.s_addr)) {
-#if DEBUGGING
-        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
-                         "1)IP-Match: %s[%s] <-> ", host, inet_ntoa(addr));
-        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
-                         "%s/", inet_ntoa(This->addr));
-        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
-                         "%s", inet_ntoa(This->mask));
-#endif
-           return 1;
-       }
-#if DEBUGGING
-       else {
-        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
-                         "1)IP-NoMatch: %s[%s] <-> ", host, inet_ntoa(addr));
-        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
-                         "%s/", inet_ntoa(This->addr));
-        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
-                         "%s", inet_ntoa(This->mask));
-       }
-#endif
-    }
-    else {
-       struct apr_sockaddr_t *reqaddr;
-
-        if (apr_sockaddr_info_get(&reqaddr, host, APR_UNSPEC, 0, 0, r->pool)
-           != APR_SUCCESS) {
-#if DEBUGGING
-           ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
-                        "2)IP-NoMatch: hostname=%s msg=Host not found", 
-                        host);
-#endif
-           return 0;
-       }
-
-       /* Try to deal with multiple IP addr's for a host */
-       /* FIXME: This needs to be able to deal with IPv6 */
-       while (reqaddr) {
-           ip = (struct in_addr *) reqaddr->ipaddr_ptr;
-           if (This->addr.s_addr == (ip->s_addr & This->mask.s_addr)) {
-#if DEBUGGING
-               ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
-                            "3)IP-Match: %s[%s] <-> ", host, 
-                            inet_ntoa(*ip));
-               ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
-                            "%s/", inet_ntoa(This->addr));
-               ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
-                            "%s", inet_ntoa(This->mask));
-#endif
-               return 1;
-           }
-#if DEBUGGING
-           else {
-                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
-                            "3)IP-NoMatch: %s[%s] <-> ", host, 
-                            inet_ntoa(*ip));
-                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
-                            "%s/", inet_ntoa(This->addr));
-                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
-                            "%s", inet_ntoa(This->mask));
-           }
-#endif
-           reqaddr = reqaddr->next;
-       }
-    }
-
-    return 0;
-}
-
-/* Return TRUE if addr represents a domain name */
-PROXY_DECLARE(int) ap_proxy_is_domainname(struct dirconn_entry *This, apr_pool_t *p)
-{
-    char *addr = This->name;
-    int i;
-
-    /* Domain name must start with a '.' */
-    if (addr[0] != '.')
-        return 0;
-
-    /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
-    for (i = 0; apr_isalnum(addr[i]) || addr[i] == '-' || addr[i] == '.'; ++i)
-        continue;
-
-#if 0
-    if (addr[i] == ':') {
-    ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
-                     "@@@@ handle optional port in proxy_is_domainname()");
-       /* @@@@ handle optional port */
-    }
-#endif
-
-    if (addr[i] != '\0')
-        return 0;
-
-    /* Strip trailing dots */
-    for (i = strlen(addr) - 1; i > 0 && addr[i] == '.'; --i)
-        addr[i] = '\0';
-
-    This->matcher = proxy_match_domainname;
-    return 1;
-}
-
-/* Return TRUE if host "host" is in domain "domain" */
-static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r)
-{
-    const char *host = proxy_get_host_of_request(r);
-    int d_len = strlen(This->name), h_len;
-
-    if (host == NULL)          /* some error was logged already */
-        return 0;
-
-    h_len = strlen(host);
-
-    /* @@@ do this within the setup? */
-    /* Ignore trailing dots in domain comparison: */
-    while (d_len > 0 && This->name[d_len - 1] == '.')
-        --d_len;
-    while (h_len > 0 && host[h_len - 1] == '.')
-        --h_len;
-    return h_len > d_len
-        && strncasecmp(&host[h_len - d_len], This->name, d_len) == 0;
-}
-
-/* Return TRUE if host represents a host name */
-PROXY_DECLARE(int) ap_proxy_is_hostname(struct dirconn_entry *This, apr_pool_t *p)
-{
-    struct apr_sockaddr_t *addr;
-    char *host = This->name;
-    int i;
-
-    /* Host names must not start with a '.' */
-    if (host[0] == '.')
-        return 0;
-
-    /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
-    for (i = 0; apr_isalnum(host[i]) || host[i] == '-' || host[i] == '.'; ++i);
-
-    if (host[i] != '\0' || apr_sockaddr_info_get(&addr, host, APR_UNSPEC, 0, 0, p) != APR_SUCCESS)
-        return 0;
-    
-    This->hostaddr = addr;
-
-    /* Strip trailing dots */
-    for (i = strlen(host) - 1; i > 0 && host[i] == '.'; --i)
-        host[i] = '\0';
-
-    This->matcher = proxy_match_hostname;
-    return 1;
-}
-
-/* Return TRUE if host "host" is equal to host2 "host2" */
-static int proxy_match_hostname(struct dirconn_entry *This, request_rec *r)
-{
-    char *host = This->name;
-    const char *host2 = proxy_get_host_of_request(r);
-    int h2_len;
-    int h1_len;
-
-    if (host == NULL || host2 == NULL)
-        return 0; /* oops! */
-
-    h2_len = strlen(host2);
-    h1_len = strlen(host);
-
-#if 0
-    struct apr_sockaddr_t *addr = *This->hostaddr;
-
-    /* Try to deal with multiple IP addr's for a host */
-    while (addr) {
-        if (addr->ipaddr_ptr == ? ? ? ? ? ? ? ? ? ? ? ? ?)
-            return 1;
-        addr = addr->next;
-    }
-#endif
-
-    /* Ignore trailing dots in host2 comparison: */
-    while (h2_len > 0 && host2[h2_len - 1] == '.')
-        --h2_len;
-    while (h1_len > 0 && host[h1_len - 1] == '.')
-        --h1_len;
-    return h1_len == h2_len
-        && strncasecmp(host, host2, h1_len) == 0;
-}
-
-/* Return TRUE if addr is to be matched as a word */
-PROXY_DECLARE(int) ap_proxy_is_word(struct dirconn_entry *This, apr_pool_t *p)
-{
-    This->matcher = proxy_match_word;
-    return 1;
-}
-
-/* Return TRUE if string "str2" occurs literally in "str1" */
-static int proxy_match_word(struct dirconn_entry *This, request_rec *r)
-{
-    const char *host = proxy_get_host_of_request(r);
-    return host != NULL && ap_strstr_c(host, This->name) != NULL;
-}
-
-/* checks whether a host in uri_addr matches proxyblock */
-PROXY_DECLARE(int) ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf, 
-                             apr_sockaddr_t *uri_addr)
-{
-    int j;
-    apr_sockaddr_t * src_uri_addr = uri_addr;
-    /* XXX FIXME: conf->noproxies->elts is part of an opaque structure */
-    for (j = 0; j < conf->noproxies->nelts; j++) {
-        struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts;
-        struct apr_sockaddr_t *conf_addr = npent[j].addr;
-        uri_addr = src_uri_addr;
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                     "proxy: checking remote machine [%s] against [%s]", uri_addr->hostname, npent[j].name);
-        if ((npent[j].name && ap_strstr_c(uri_addr->hostname, npent[j].name))
-            || npent[j].name[0] == '*') {
-            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
-                         "proxy: connect to remote machine %s blocked: name %s matched", uri_addr->hostname, npent[j].name);
-            return HTTP_FORBIDDEN;
-        }
-        while (conf_addr) {
-            while (uri_addr) {
-                char *conf_ip;
-                char *uri_ip;
-                apr_sockaddr_ip_get(&conf_ip, conf_addr);
-                apr_sockaddr_ip_get(&uri_ip, uri_addr);
-                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                             "proxy: ProxyBlock comparing %s and %s", conf_ip, uri_ip);
-                if (!apr_strnatcasecmp(conf_ip, uri_ip)) {
-                    ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
-                                 "proxy: connect to remote machine %s blocked: IP %s matched", uri_addr->hostname, conf_ip);
-                    return HTTP_FORBIDDEN;
-                }
-                uri_addr = uri_addr->next;
-            }
-            conf_addr = conf_addr->next;
-        }
-    }
-    return OK;
-}
-
-/* set up the minimal filter set */
-PROXY_DECLARE(int) ap_proxy_pre_http_request(conn_rec *c, request_rec *r)
-{
-    ap_add_input_filter("HTTP_IN", NULL, r, c);
-    return OK;
-}
-
-/* converts a series of buckets into a string 
- * XXX: BillS says this function performs essentially the same function as 
- * ap_rgetline() in protocol.c. Deprecate this function and use ap_rgetline() 
- * instead? I think ap_proxy_string_read() will not work properly on non ASCII
- * (EBCDIC) machines either.
- */
-PROXY_DECLARE(apr_status_t) ap_proxy_string_read(conn_rec *c, apr_bucket_brigade *bb,
-                                                 char *buff, apr_size_t bufflen, int *eos)
-{
-    apr_bucket *e;
-    apr_status_t rv;
-    char *pos = buff;
-    char *response;
-    int found = 0;
-    apr_size_t len;
-
-    /* start with an empty string */
-    buff[0] = 0;
-    *eos = 0;
-
-    /* loop through each brigade */
-    while (!found) {
-        /* get brigade from network one line at a time */
-        if (APR_SUCCESS != (rv = ap_get_brigade(c->input_filters, bb, 
-                                                AP_MODE_GETLINE,
-                                                APR_BLOCK_READ,
-                                                0))) {
-            return rv;
-        }
-        /* loop through each bucket */
-        while (!found) {
-            if (*eos || APR_BRIGADE_EMPTY(bb)) {
-                /* The connection aborted or timed out */
-                return APR_ECONNABORTED;
-            }
-            e = APR_BRIGADE_FIRST(bb);
-            if (APR_BUCKET_IS_EOS(e)) {
-                *eos = 1;
-            }
-            else {
-                if (APR_SUCCESS != apr_bucket_read(e, (const char **)&response, &len, APR_BLOCK_READ)) {
-                    return rv;
-                }
-                /* is string LF terminated? 
-                 * XXX: This check can be made more efficient by simply checking 
-                 * if the last character in the 'response' buffer is an ASCII_LF.
-                 * See ap_rgetline() for an example.
-                 */
-                if (memchr(response, APR_ASCII_LF, len)) {
-                    found = 1;
-                }
-                /* concat strings until buff is full - then throw the data away */
-                if (len > ((bufflen-1)-(pos-buff))) {
-                    len = (bufflen-1)-(pos-buff);
-                }
-                if (len > 0) {
-                    pos = apr_cpystrn(pos, response, len);
-                }
-            }
-            APR_BUCKET_REMOVE(e);
-            apr_bucket_destroy(e);
-        }
-    }
-
-    return APR_SUCCESS;
-}
-
-/* unmerge an element in the table */
-PROXY_DECLARE(void) ap_proxy_table_unmerge(apr_pool_t *p, apr_table_t *t, char *key)
-{
-    apr_off_t offset = 0;
-    apr_off_t count = 0;
-    char *value = NULL;
-
-    /* get the value to unmerge */
-    const char *initial = apr_table_get(t, key);
-    if (!initial) {
-        return;
-    }
-    value = apr_pstrdup(p, initial);
-
-    /* remove the value from the headers */
-    apr_table_unset(t, key);
-
-    /* find each comma */
-    while (value[count]) {
-        if (value[count] == ',') {
-            value[count] = 0;
-            apr_table_add(t, key, value + offset);
-            offset = count + 1;
-        }
-        count++;
-    }
-    apr_table_add(t, key, value + offset);
-}
-
-PROXY_DECLARE(proxy_balancer *) ap_proxy_get_balancer(apr_pool_t *p,
-                                                      proxy_server_conf *conf,
-                                                      const char *url)
-{
-    proxy_balancer *balancer;
-    char *c, *uri = apr_pstrdup(p, url);
-    int i;
-    
-    c = strchr(uri, ':');   
-    if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')
-       return NULL;
-    /* remove path from uri */
-    if ((c = strchr(c + 3, '/')))
-        *c = '\0';
-    balancer = (proxy_balancer *)conf->balancers->elts;
-    for (i = 0; i < conf->balancers->nelts; i++) {
-        if (strcasecmp(balancer->name, uri) == 0)
-            return balancer;
-        balancer++;
-    }
-    return NULL;
-}
-
-PROXY_DECLARE(const char *) ap_proxy_add_balancer(proxy_balancer **balancer,
-                                                  apr_pool_t *p,
-                                                  proxy_server_conf *conf,
-                                                  const char *url)
-{
-    char *c, *q, *uri = apr_pstrdup(p, url);
-
-    c = strchr(uri, ':');   
-    if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')
-       return "Bad syntax for a balancer name";
-    /* remove path from uri */
-    if ((q = strchr(c + 3, '/')))
-        *q = '\0';
-
-    ap_str_tolower(uri);
-    *balancer = apr_array_push(conf->balancers);
-    memset(*balancer, 0, sizeof(proxy_balancer));
-
-    (*balancer)->name = uri;
-    (*balancer)->workers = apr_array_make(p, 5, sizeof(proxy_worker));
-    /* XXX Is this a right place to create mutex */
-#if APR_HAS_THREADS
-    if (apr_thread_mutex_create(&((*balancer)->mutex),
-                APR_THREAD_MUTEX_DEFAULT, p) != APR_SUCCESS) {
-        /* XXX: Do we need to log something here */
-        return "can not create thread mutex";
-    }
-#endif
-
-    return NULL;
-}
-
-PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
-                                                  proxy_server_conf *conf,
-                                                  const char *url)
-{
-    proxy_worker *worker;
-    char *c, *uri = apr_pstrdup(p, url);
-    int i;
-    
-    c = strchr(uri, ':');   
-    if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')
-       return NULL;
-    /* remove path from uri */
-    if ((c = strchr(c + 3, '/')))
-        *c = '\0';
-
-    worker = (proxy_worker *)conf->workers->elts;
-    for (i = 0; i < conf->workers->nelts; i++) {
-        if (strcasecmp(worker->name, uri) == 0) {
-            return worker;
-        }
-        worker++;
-    }
-    return NULL;
-}
-
-#if APR_HAS_THREADS
-static apr_status_t conn_pool_cleanup(void *theworker)
-{
-    proxy_worker *worker = (proxy_worker *)theworker;
-    if (worker->cp->res) {
-        worker->cp->pool = NULL;
-        apr_reslist_destroy(worker->cp->res);
-    }
-    return APR_SUCCESS;
-}
-#endif
-
-static void init_conn_pool(apr_pool_t *p, proxy_worker *worker)
-{
-    apr_pool_t *pool;
-    proxy_conn_pool *cp;
-    
-    /* Create a connection pool's subpool. 
-     * This pool is used for connection recycling.
-     * Once the worker is added it is never removed but
-     * it can be disabled.
-     */
-    apr_pool_create(&pool, p);
-    /* Alloc from the same pool as worker.
-     * proxy_conn_pool is permanently attached to the worker. 
-     */
-    cp = (proxy_conn_pool *)apr_pcalloc(p, sizeof(proxy_conn_pool));
-    cp->pool = pool;    
-    worker->cp = cp;
-}
-
-PROXY_DECLARE(const char *) ap_proxy_add_worker(proxy_worker **worker,
-                                                apr_pool_t *p,
-                                                proxy_server_conf *conf,
-                                                const char *url)
-{
-    char *c, *q, *uri = apr_pstrdup(p, url);
-    int port;
-    
-    c = strchr(uri, ':');   
-    if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')
-       return "Bad syntax for a remote proxy server";
-    /* remove path from uri */
-    if ((q = strchr(c + 3, '/')))
-        *q = '\0';
-
-    q = strchr(c + 3, ':');
-    if (q != NULL) {
-        if (sscanf(q + 1, "%u", &port) != 1 || port > 65535) {
-            return "Bad syntax for a remote proxy server (bad port number)";
-        }
-    }
-    else
-        port = -1;
-    ap_str_tolower(uri);
-    *worker = apr_array_push(conf->workers);
-    memset(*worker, 0, sizeof(proxy_worker));
-    (*worker)->name = apr_pstrdup(p, uri);
-    *c = '\0';
-    (*worker)->scheme = uri;
-    (*worker)->hostname = c + 3;
-
-    if (port == -1)
-        port = apr_uri_port_of_scheme((*worker)->scheme);
-    (*worker)->port = port;
-    (*worker)->id   = lb_workers;
-    /* Increase the total worker count */
-    ++lb_workers;
-    init_conn_pool(p, *worker);
-
-    return NULL;
-}
-
-PROXY_DECLARE(proxy_worker *) ap_proxy_create_worker(apr_pool_t *p)
-{
-
-    proxy_worker *worker;
-    worker = (proxy_worker *)apr_pcalloc(p, sizeof(proxy_worker));
-    worker->id = lb_workers;
-    /* Increase the total worker count */
-    ++lb_workers;
-    init_conn_pool(p, worker);
-
-    return worker;
-}
-
-PROXY_DECLARE(void) 
-ap_proxy_add_worker_to_balancer(apr_pool_t *pool, proxy_balancer *balancer,
-                                proxy_worker *worker)
-{
-    proxy_worker *runtime;
-
-#if PROXY_HAS_SCOREBOARD
-    int mpm_daemons;
-
-    ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &mpm_daemons);
-    /* Check if we are prefork or single child */
-    if (worker->hmax && mpm_daemons > 1) {
-        /* Check only if workers_limit is set */
-        if (lb_workers_limit && (lb_workers + 1) > lb_workers_limit) {
-            ap_log_perror(APLOG_MARK, APLOG_ERR, 0, pool,
-                          "proxy: Can not add worker (%s) to balancer (%s)."
-                          " Dynamic limit reached.",
-                          worker->name, balancer->name);
-            return;
-        }
-    }
-#endif
-    runtime = apr_array_push(balancer->workers);
-    memcpy(runtime, worker, sizeof(proxy_worker));
-    runtime->id = lb_workers;
-    /* Increase the total runtime count */
-    ++lb_workers;
-
-}
-
-PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
-                                        proxy_balancer **balancer,
-                                        request_rec *r,
-                                        proxy_server_conf *conf, char **url)
-{
-    int access_status;
-    
-    access_status = proxy_run_pre_request(worker, balancer, r, conf, url);
-    if (access_status == DECLINED && *balancer == NULL) {
-        *worker = ap_proxy_get_worker(r->pool, conf, *url);
-        if (*worker) {
-            *balancer = NULL;
-            access_status = OK;
-        }
-        else if (r->proxyreq == PROXYREQ_PROXY) {
-            if (conf->forward) {
-                *balancer = NULL;
-                *worker = conf->forward;
-                access_status = OK;
-            }
-        }
-    }
-    else if (access_status == DECLINED && balancer != NULL) {
-        /* All the workers are busy */
-        access_status = HTTP_SERVICE_UNAVAILABLE;
-    }
-    return access_status;
-}
-
-PROXY_DECLARE(int) ap_proxy_post_request(proxy_worker *worker,
-                                         proxy_balancer *balancer,
-                                         request_rec *r,
-                                         proxy_server_conf *conf)
-{
-    int access_status;
-    if (balancer)
-        access_status = proxy_run_post_request(worker, balancer, r, conf);
-    else { 
-        
-
-        access_status = OK;
-    }
-
-    return access_status;
-}
-
-/* DEPRECATED */
-PROXY_DECLARE(int) ap_proxy_connect_to_backend(apr_socket_t **newsock,
-                                               const char *proxy_function,
-                                               apr_sockaddr_t *backend_addr,
-                                               const char *backend_name,
-                                               proxy_server_conf *conf,
-                                               server_rec *s,
-                                               apr_pool_t *p)
-{
-    apr_status_t rv;
-    int connected = 0;
-    int loglevel;
-    
-    while (backend_addr && !connected) {
-        if ((rv = apr_socket_create(newsock, backend_addr->family,
-                                    SOCK_STREAM, 0, p)) != APR_SUCCESS) {
-            loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
-            ap_log_error(APLOG_MARK, loglevel, rv, s,
-                         "proxy: %s: error creating fam %d socket for target %s",
-                         proxy_function,
-                         backend_addr->family,
-                         backend_name);
-            /* this could be an IPv6 address from the DNS but the
-             * local machine won't give us an IPv6 socket; hopefully the
-             * DNS returned an additional address to try
-             */
-            backend_addr = backend_addr->next;
-            continue;
-        }
-
-#if !defined(TPF) && !defined(BEOS)
-        if (conf->recv_buffer_size > 0 &&
-            (rv = apr_socket_opt_set(*newsock, APR_SO_RCVBUF,
-                                     conf->recv_buffer_size))) {
-            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
-                         "apr_socket_opt_set(SO_RCVBUF): Failed to set "
-                         "ProxyReceiveBufferSize, using default");
-        }
-#endif
-
-        /* Set a timeout on the socket */
-        if (conf->timeout_set == 1) {
-            apr_socket_timeout_set(*newsock, conf->timeout);
-        }
-        else {
-             apr_socket_timeout_set(*newsock, s->timeout);
-        }
-
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                     "proxy: %s: fam %d socket created to connect to %s",
-                     proxy_function, backend_addr->family, backend_name);
-
-        /* make the connection out of the socket */
-        rv = apr_socket_connect(*newsock, backend_addr);
-
-        /* if an error occurred, loop round and try again */
-        if (rv != APR_SUCCESS) {
-            apr_socket_close(*newsock);
-            loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
-            ap_log_error(APLOG_MARK, loglevel, rv, s,
-                         "proxy: %s: attempt to connect to %pI (%s) failed",
-                         proxy_function,
-                         backend_addr,
-                         backend_name);
-            backend_addr = backend_addr->next;
-            continue;
-        }
-        connected = 1;
-    }
-    return connected ? 0 : 1;
-}
-
-static apr_status_t connection_cleanup(void *theconn)
-{
-    proxy_conn_rec *conn = (proxy_conn_rec *)theconn;
-    proxy_worker *worker = conn->worker;
-    
-    /* If the connection pool is NULL the worker
-     * cleanup has been run. Just return.
-     */
-    if (!worker->cp)
-        return APR_SUCCESS;
-
-    /* deterimine if the connection need to be closed */
-    if (conn->close_on_recycle || conn->close) {
-        apr_pool_t *p = conn->pool;
-        apr_pool_clear(conn->pool);
-        memset(conn, 0, sizeof(proxy_conn_rec));
-        conn->pool = p;
-        conn->worker = worker;
-    }
-#if APR_HAS_THREADS
-    if (worker->hmax && worker->cp->res) {
-        apr_reslist_release(worker->cp->res, (void *)conn);
-    }
-    else
-#endif
-    {
-        worker->cp->conn = conn;
-    }
-
-    /* Allways return the SUCCESS */
-    return APR_SUCCESS;
-}
-
-/* reslist constructor */
-static apr_status_t connection_constructor(void **resource, void *params,
-                                           apr_pool_t *pool)
-{
-    apr_pool_t *ctx;
-    proxy_conn_rec *conn;
-    proxy_worker *worker = (proxy_worker *)params;
-    
-    /* Create the subpool for each connection
-     * This keeps the memory consumption constant
-     * when disconnecting from backend.
-     */
-    apr_pool_create(&ctx, pool);
-    conn = apr_pcalloc(pool, sizeof(proxy_conn_rec));
-
-    conn->pool   = ctx;
-    conn->worker = worker;
-    *resource = conn;
-
-    return APR_SUCCESS;
-}
-
-/* reslist destructor */
-static apr_status_t connection_destructor(void *resource, void *params,
-                                          apr_pool_t *pool)
-{
-    proxy_conn_rec *conn = (proxy_conn_rec *)resource;
-
-    /* Destroy the pool only if not called from reslist_destroy */    
-    if (conn->worker->cp->pool)
-        apr_pool_destroy(conn->pool);
-
-    return APR_SUCCESS;
-}
-
-PROXY_DECLARE(void) ap_proxy_initialize_worker_share(proxy_server_conf *conf,
-                                                     proxy_worker *worker)
-{
-#if PROXY_HAS_SCOREBOARD
-    lb_score *score = NULL;
-#else
-    void *score = NULL;
-#endif
-#if PROXY_HAS_SCOREBOARD
-        /* Get scoreboard slot */
-    if (ap_scoreboard_image)
-        score = ap_get_scoreboard_lb(worker->id);
-#endif
-    if (!score)
-        score = apr_pcalloc(conf->pool, sizeof(proxy_worker_stat));
-    worker->s = (proxy_worker_stat *)score;
-    if (worker->route)
-        strcpy(worker->s->route, worker->route);
-    if (worker->redirect)
-        strcpy(worker->s->redirect, worker->redirect);
-}
-
-PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, server_rec *s)
-{
-    apr_status_t rv;
-
-#if APR_HAS_THREADS
-    int mpm_threads;
-
-    ap_mpm_query(AP_MPMQ_MAX_THREADS, &mpm_threads);
-    if (mpm_threads > 1) {
-        /* Set hard max to no more then mpm_threads */
-        if (worker->hmax == 0 || worker->hmax > mpm_threads)
-            worker->hmax = mpm_threads;
-        if (worker->smax == 0 || worker->smax > worker->hmax)
-            worker->smax = worker->hmax;
-        /* Set min to be lower then smax */
-        if (worker->min > worker->smax)
-            worker->min = worker->smax; 
-    }
-    else {
-        /* This will supress the apr_reslist creation */
-        worker->min = worker->smax = worker->hmax = 0;
-    }
-    if (worker->hmax) {
-        rv = apr_reslist_create(&(worker->cp->res),
-                                worker->min, worker->smax,
-                                worker->hmax, worker->ttl,
-                                connection_constructor, connection_destructor,
-                                worker, worker->cp->pool);
-
-        apr_pool_cleanup_register(worker->cp->pool, (void *)worker,
-                                  conn_pool_cleanup,
-                                  apr_pool_cleanup_null);
-
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                     "proxy: initialized worker for (%s) min=%d max=%d smax=%d",
-                      worker->hostname, worker->min, worker->hmax, worker->smax);
-
-#if (APR_MAJOR_VERSION > 0)
-        /* Set the acquire timeout */
-        if (rv == APR_SUCCESS && worker->acquire_set)
-            apr_reslist_timeout_set(worker->cp->res, worker->acquire);
-#endif
-    }
-    else
-#endif
-    {
-        
-        rv = connection_constructor((void **)&(worker->cp->conn), worker, worker->cp->pool);
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                     "proxy: initialized single connection worker for (%s)",
-                      worker->hostname);
-    }
-    if (rv == APR_SUCCESS)
-        worker->s->status |= PROXY_WORKER_INITIALIZED;
-    /* Set default parameters */
-    if (!worker->retry)
-        worker->retry = apr_time_from_sec(PROXY_WORKER_DEFAULT_RETRY);
-    return rv;
-}
-
-PROXY_DECLARE(int) ap_proxy_retry_worker(const char *proxy_function,
-                                         proxy_worker *worker,
-                                         server_rec *s)
-{
-    if (worker->s->status & PROXY_WORKER_IN_ERROR) {
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                    "proxy: %s: retrying the worker for (%s)",
-                     proxy_function, worker->hostname);
-        if (apr_time_now() > worker->s->error_time + worker->retry) {
-            ++worker->s->retries;
-            worker->s->status &= ~PROXY_WORKER_IN_ERROR;
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                         "proxy: %s: worker for (%s) has been marked for retry",
-                         proxy_function, worker->hostname);
-            return OK;
-        }
-        else
-            return DECLINED;
-    }
-    else
-        return OK;
-}
-
-PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function,
-                                               proxy_conn_rec **conn,
-                                               proxy_worker *worker,
-                                               server_rec *s)
-{
-    apr_status_t rv;
-
-    if (!PROXY_WORKER_IS_USABLE(worker)) {
-        /* Retry the worker */
-        ap_proxy_retry_worker(proxy_function, worker, s);
-    
-        if (!PROXY_WORKER_IS_USABLE(worker)) {
-            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
-                         "proxy: %s: disabled connection for (%s)",
-                         proxy_function, worker->hostname);
-            return HTTP_SERVICE_UNAVAILABLE;
-        }
-    }
-#if APR_HAS_THREADS
-    if (worker->hmax) {
-        rv = apr_reslist_acquire(worker->cp->res, (void **)conn);
-    }
-    else
-#endif
-    {
-        /* create the new connection if the previous was destroyed */
-        if (!worker->cp->conn)
-            connection_constructor((void **)conn, worker, worker->cp->pool);
-        else {
-            *conn = worker->cp->conn;
-            worker->cp->conn = NULL;
-        }
-        rv = APR_SUCCESS;
-    }
-
-    if (rv != APR_SUCCESS) {
-        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
-                     "proxy: %s: failed to acquire connection for (%s)",
-                     proxy_function, worker->hostname);
-        return HTTP_SERVICE_UNAVAILABLE;
-    }
-    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                 "proxy: %s: has acquired connection for (%s)",
-                 proxy_function, worker->hostname);
-
-    (*conn)->worker = worker;
-    (*conn)->close  = 0;
-    (*conn)->close_on_recycle = 0;
-
-    return OK;
-}
-
-PROXY_DECLARE(int) ap_proxy_release_connection(const char *proxy_function,
-                                               proxy_conn_rec *conn,
-                                               server_rec *s)
-{
-    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                 "proxy: %s: has released connection for (%s)",
-                 proxy_function, conn->worker->hostname);
-    /* If there is a connection kill it's cleanup */
-    if (conn->connection) {
-        apr_pool_cleanup_kill(conn->connection->pool, conn, connection_cleanup);
-        conn->connection = NULL;
-    }
-    connection_cleanup(conn);
-
-    return OK;
-}
-
-PROXY_DECLARE(int)
-ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
-                              proxy_server_conf *conf,
-                              proxy_worker *worker,
-                              proxy_conn_rec *conn,
-                              apr_uri_t *uri,
-                              char **url,
-                              const char *proxyname,
-                              apr_port_t proxyport,
-                              char *server_portstr,
-                              int server_portstr_size)
-{
-    int server_port;
-    apr_status_t err = APR_SUCCESS;
-    /*
-     * Break up the URL to determine the host to connect to
-     */
-
-    /* we break the URL into host, port, uri */
-    if (APR_SUCCESS != apr_uri_parse(p, *url, uri)) {
-        return ap_proxyerror(r, HTTP_BAD_REQUEST,
-                             apr_pstrcat(p,"URI cannot be parsed: ", *url,
-                                         NULL));
-    }
-    if (!uri->port) {
-        uri->port = apr_uri_port_of_scheme(uri->scheme);
-    }
-
-    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                 "proxy: connecting %s to %s:%d", *url, uri->hostname,
-                 uri->port);
-
-    /* allocate these out of the specified connection pool 
-     * The scheme handler decides if this is permanent or
-     * short living pool.
-     */
-    /* are we connecting directly, or via a proxy? */
-    if (!proxyname) {
-        *url = apr_pstrcat(p, uri->path, uri->query ? "?" : "",
-                           uri->query ? uri->query : "",
-                           uri->fragment ? "#" : "",
-                           uri->fragment ? uri->fragment : "", NULL);
-    }
-    if (!conn->hostname) {
-        if (proxyname) {
-            conn->hostname = apr_pstrdup(conn->pool, proxyname);
-            conn->port = proxyport;
-        } else {
-            conn->hostname = apr_pstrdup(conn->pool, uri->hostname);
-            conn->port = uri->port;
-        }
-    }
-    /* TODO: add address cache for forward proxies */
-    conn->addr = worker->cp->addr;
-    if (r->proxyreq == PROXYREQ_PROXY) {
-        err = apr_sockaddr_info_get(&(conn->addr),
-                                    conn->hostname, APR_UNSPEC,
-                                    conn->port, 0,
-                                    conn->pool);
-    }
-    else if (!worker->cp->addr) {
-        /* Worker can have the single constant backend adress.
-         * The single DNS lookup is used once per worker.
-        * If dynamic change is needed then set the addr to NULL
-        * inside dynamic config to force the lookup.
-        */
-        err = apr_sockaddr_info_get(&(worker->cp->addr),
-                                    conn->hostname, APR_UNSPEC,
-                                    conn->port, 0,
-                                    worker->cp->pool);
-        conn->addr = worker->cp->addr;
-    }
-    if (err != APR_SUCCESS) {
-        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
-                             apr_pstrcat(p, "DNS lookup failure for: ",
-                                         conn->hostname, NULL));
-    }
-
-    /* Get the server port for the Via headers */
-    {
-        server_port = ap_get_server_port(r);
-        if (ap_is_default_port(server_port, r)) {
-            strcpy(server_portstr,"");
-        } else {
-            apr_snprintf(server_portstr, server_portstr_size, ":%d",
-                         server_port);
-        }
-    }
-
-    /* check if ProxyBlock directive on this host */
-    if (OK != ap_proxy_checkproxyblock(r, conf, conn->addr)) {
-        return ap_proxyerror(r, HTTP_FORBIDDEN,
-                             "Connect to remote machine blocked");
-    }
-    return OK;
-}
-
-static int is_socket_connected(apr_socket_t *sock)
-
-{
-    apr_size_t buffer_len = 1;
-    char test_buffer[1]; 
-    apr_status_t socket_status;
-    apr_interval_time_t current_timeout;
-    
-    /* save timeout */
-    apr_socket_timeout_get(sock, &current_timeout);
-    /* set no timeout */
-    apr_socket_timeout_set(sock, 0);
-    socket_status = apr_socket_recv(sock, test_buffer, &buffer_len);
-    /* put back old timeout */
-    apr_socket_timeout_set(sock, current_timeout);
-    if (APR_STATUS_IS_EOF(socket_status))
-        return 0;
-    else
-        return 1;
-}
-
-PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
-                                            proxy_conn_rec *conn,
-                                            proxy_worker *worker,
-                                            server_rec *s)
-{
-    apr_status_t rv;
-    int connected = 0;
-    int loglevel;
-    apr_sockaddr_t *backend_addr = conn->addr;
-    apr_socket_t *newsock;
-    
-    if (conn->sock) {
-        /* This increases the connection pool size
-         * but the number of dropped connections is
-         * relatively small compared to connection lifetime
-         */
-        if (!(connected = is_socket_connected(conn->sock))) {        
-            apr_socket_close(conn->sock);
-            conn->sock = NULL;
-        }
-    }
-    while (backend_addr && !connected) {
-        if ((rv = apr_socket_create(&newsock, backend_addr->family,
-                                SOCK_STREAM, APR_PROTO_TCP,
-                                conn->pool)) != APR_SUCCESS) {
-            loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
-            ap_log_error(APLOG_MARK, loglevel, rv, s,
-                         "proxy: %s: error creating fam %d socket for target %s",
-                         proxy_function,
-                         backend_addr->family,
-                         worker->hostname);
-            /* this could be an IPv6 address from the DNS but the
-             * local machine won't give us an IPv6 socket; hopefully the
-             * DNS returned an additional address to try
-             */
-            backend_addr = backend_addr->next;
-            continue;
-        }
-
-#if !defined(TPF) && !defined(BEOS)
-        if (worker->recv_buffer_size > 0 &&
-            (rv = apr_socket_opt_set(newsock, APR_SO_RCVBUF,
-                                     worker->recv_buffer_size))) {
-            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
-                         "apr_socket_opt_set(SO_RCVBUF): Failed to set "
-                         "ProxyReceiveBufferSize, using default");
-        }
-#endif
-
-        /* Set a timeout on the socket */
-        if (worker->timeout_set == 1) {
-            apr_socket_timeout_set(newsock, worker->timeout);
-        }
-        else {
-             apr_socket_timeout_set(newsock, s->timeout);
-        }
-        /* Set a keepalive option */
-        if (worker->keepalive) {
-            if ((rv = apr_socket_opt_set(newsock, 
-                            APR_SO_KEEPALIVE, 1)) != APR_SUCCESS) {
-                ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
-                             "apr_socket_opt_set(SO_KEEPALIVE): Failed to set"
-                             " Keepalive");
-            }
-        }
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                     "proxy: %s: fam %d socket created to connect to %s",
-                     proxy_function, backend_addr->family, worker->hostname);
-
-        /* make the connection out of the socket */
-        rv = apr_socket_connect(newsock, backend_addr);
-
-        /* if an error occurred, loop round and try again */
-        if (rv != APR_SUCCESS) {
-            apr_socket_close(newsock);
-            loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
-            ap_log_error(APLOG_MARK, loglevel, rv, s,
-                         "proxy: %s: attempt to connect to %pI (%s) failed",
-                         proxy_function,
-                         backend_addr,
-                         worker->hostname);
-            backend_addr = backend_addr->next;
-            continue;
-        }
-        
-        conn->sock   = newsock;
-        connected    = 1;
-    }
-    /* Put the entire worker to error state if
-     * the PROXY_WORKER_IGNORE_ERRORS flag is not set.
-     * Altrough some connections may be alive
-     * no further connections to the worker could be made
-     */
-    if (!connected && PROXY_WORKER_IS_USABLE(worker) &&
-        !(worker->s->status & PROXY_WORKER_IGNORE_ERRORS)) {
-        worker->s->status |= PROXY_WORKER_IN_ERROR;
-        worker->s->error_time = apr_time_now();
-        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
-            "ap_proxy_connect_backend disabling worker for (%s)",
-            worker->hostname);
-    }
-    else {
-        worker->s->error_time = 0;
-        worker->s->retries = 0;
-    }
-    return connected ? OK : DECLINED;
-}
-
-PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function,
-                                              proxy_conn_rec *conn,
-                                              conn_rec *c,
-                                              server_rec *s)
-{
-    apr_sockaddr_t *backend_addr = conn->addr;
-
-    /* The socket is now open, create a new backend server connection 
-    * 
-    */
-    conn->connection = ap_run_create_connection(c->pool, s, conn->sock,
-                                                c->id, c->sbh,
-                                                c->bucket_alloc);
-
-    if (!conn->connection) {
-        /* the peer reset the connection already; ap_run_create_connection() 
-        * closed the socket
-        */
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
-                     s, "proxy: %s: an error occurred creating a "
-                     "new connection to %pI (%s)", proxy_function,
-                     backend_addr, conn->hostname);
-        /* XXX: Will be closed when proxy_conn is closed */
-        apr_socket_close(conn->sock);
-        conn->sock = NULL;
-        return HTTP_INTERNAL_SERVER_ERROR;
-    }
-    /* register the connection cleanup to client connection
-     * so that the connection can be closed or reused
-     */
-    apr_pool_cleanup_register(c->pool, (void *)conn,
-                              connection_cleanup,
-                              apr_pool_cleanup_null);      
-
-    /* For ssl connection to backend */
-    if (conn->is_ssl) {
-        if (!ap_proxy_ssl_enable(conn->connection)) {
-            ap_log_error(APLOG_MARK, APLOG_ERR, 0,
-                         s, "proxy: %s: failed to enable ssl support "
-                         "for %pI (%s)", proxy_function, 
-                         backend_addr, conn->hostname);
-            return HTTP_INTERNAL_SERVER_ERROR;
-        }
-    }
-    else {
-        /* TODO: See if this will break FTP */
-        ap_proxy_ssl_disable(conn->connection);
-    }
-
-    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                 "proxy: %s: connection complete to %pI (%s)",
-                 proxy_function, backend_addr, conn->hostname);
-
-    /* set up the connection filters */
-    ap_run_pre_connection(conn->connection, conn->sock);
-
-    return OK;
-}
-
-int ap_proxy_lb_workers(void)
-{
-    /* Set the dynamic #workers limit */
-    lb_workers_limit = lb_workers + PROXY_DYNAMIC_BALANCER_LIMIT;
-    return lb_workers_limit;
-}
+/* Copyright 1999-2004 The Apache Software Foundation\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/* Utility routines for Apache proxy */\r
+#include "mod_proxy.h"\r
+#include "ap_mpm.h"\r
+#include "scoreboard.h"\r
+#include "apr_version.h"\r
+\r
+#if APR_HAVE_UNISTD_H\r
+#include <unistd.h>         /* for getpid() */\r
+#endif\r
+\r
+#if (APR_MAJOR_VERSION < 1)\r
+#undef apr_socket_create\r
+#define apr_socket_create apr_socket_create_ex\r
+#endif\r
+\r
+/* Global balancer counter */\r
+int PROXY_DECLARE_DATA proxy_lb_workers = 0;\r
+static int lb_workers_limit = 0;\r
+\r
+static int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r);\r
+static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r);\r
+static int proxy_match_hostname(struct dirconn_entry *This, request_rec *r);\r
+static int proxy_match_word(struct dirconn_entry *This, request_rec *r);\r
+\r
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, create_req, \r
+                                   (request_rec *r, request_rec *pr), (r, pr),\r
+                                   OK, DECLINED)\r
+\r
+/* already called in the knowledge that the characters are hex digits */\r
+PROXY_DECLARE(int) ap_proxy_hex2c(const char *x)\r
+{\r
+    int i, ch;\r
+\r
+#if !APR_CHARSET_EBCDIC\r
+    ch = x[0];\r
+    if (apr_isdigit(ch))\r
+       i = ch - '0';\r
+    else if (apr_isupper(ch))\r
+       i = ch - ('A' - 10);\r
+    else\r
+       i = ch - ('a' - 10);\r
+    i <<= 4;\r
+\r
+    ch = x[1];\r
+    if (apr_isdigit(ch))\r
+       i += ch - '0';\r
+    else if (apr_isupper(ch))\r
+       i += ch - ('A' - 10);\r
+    else\r
+       i += ch - ('a' - 10);\r
+    return i;\r
+#else /*APR_CHARSET_EBCDIC*/\r
+    /* we assume that the hex value refers to an ASCII character\r
+     * so convert to EBCDIC so that it makes sense locally;\r
+     *\r
+     * example:\r
+     *\r
+     * client specifies %20 in URL to refer to a space char;\r
+     * at this point we're called with EBCDIC "20"; after turning\r
+     * EBCDIC "20" into binary 0x20, we then need to assume that 0x20\r
+     * represents an ASCII char and convert 0x20 to EBCDIC, yielding\r
+     * 0x40\r
+     */\r
+    char buf[1];\r
+\r
+    if (1 == sscanf(x, "%2x", &i)) {\r
+        buf[0] = i & 0xFF;\r
+        ap_xlate_proto_from_ascii(buf, 1);\r
+        return buf[0];\r
+    }\r
+    else {\r
+        return 0;\r
+    }\r
+#endif /*APR_CHARSET_EBCDIC*/\r
+}\r
+\r
+PROXY_DECLARE(void) ap_proxy_c2hex(int ch, char *x)\r
+{\r
+#if !APR_CHARSET_EBCDIC\r
+    int i;\r
+\r
+    x[0] = '%';\r
+    i = (ch & 0xF0) >> 4;\r
+    if (i >= 10)\r
+       x[1] = ('A' - 10) + i;\r
+    else\r
+       x[1] = '0' + i;\r
+\r
+    i = ch & 0x0F;\r
+    if (i >= 10)\r
+       x[2] = ('A' - 10) + i;\r
+    else\r
+       x[2] = '0' + i;\r
+#else /*APR_CHARSET_EBCDIC*/\r
+    static const char ntoa[] = { "0123456789ABCDEF" };\r
+    char buf[1];\r
+\r
+    ch &= 0xFF;\r
+\r
+    buf[0] = ch;\r
+    ap_xlate_proto_to_ascii(buf, 1);\r
+\r
+    x[0] = '%';\r
+    x[1] = ntoa[(buf[0] >> 4) & 0x0F];\r
+    x[2] = ntoa[buf[0] & 0x0F];\r
+    x[3] = '\0';\r
+#endif /*APR_CHARSET_EBCDIC*/\r
+}\r
+\r
+/*\r
+ * canonicalise a URL-encoded string\r
+ */\r
+\r
+/*\r
+ * Convert a URL-encoded string to canonical form.\r
+ * It decodes characters which need not be encoded,\r
+ * and encodes those which must be encoded, and does not touch\r
+ * those which must not be touched.\r
+ */\r
+PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, enum enctype t,\r
+       int isenc)\r
+{\r
+    int i, j, ch;\r
+    char *y;\r
+    char *allowed;     /* characters which should not be encoded */\r
+    char *reserved;    /* characters which much not be en/de-coded */\r
+\r
+/* N.B. in addition to :@&=, this allows ';' in an http path\r
+ * and '?' in an ftp path -- this may be revised\r
+ * \r
+ * Also, it makes a '+' character in a search string reserved, as\r
+ * it may be form-encoded. (Although RFC 1738 doesn't allow this -\r
+ * it only permits ; / ? : @ = & as reserved chars.)\r
+ */\r
+    if (t == enc_path)\r
+       allowed = "$-_.+!*'(),;:@&=";\r
+    else if (t == enc_search)\r
+       allowed = "$-_.!*'(),;:@&=";\r
+    else if (t == enc_user)\r
+       allowed = "$-_.+!*'(),;@&=";\r
+    else if (t == enc_fpath)\r
+       allowed = "$-_.+!*'(),?:@&=";\r
+    else                       /* if (t == enc_parm) */\r
+       allowed = "$-_.+!*'(),?/:@&=";\r
+\r
+    if (t == enc_path)\r
+       reserved = "/";\r
+    else if (t == enc_search)\r
+       reserved = "+";\r
+    else\r
+       reserved = "";\r
+\r
+    y = apr_palloc(p, 3 * len + 1);\r
+\r
+    for (i = 0, j = 0; i < len; i++, j++) {\r
+/* always handle '/' first */\r
+       ch = x[i];\r
+       if (strchr(reserved, ch)) {\r
+           y[j] = ch;\r
+           continue;\r
+       }\r
+/* decode it if not already done */\r
+       if (isenc && ch == '%') {\r
+           if (!apr_isxdigit(x[i + 1]) || !apr_isxdigit(x[i + 2]))\r
+               return NULL;\r
+           ch = ap_proxy_hex2c(&x[i + 1]);\r
+           i += 2;\r
+           if (ch != 0 && strchr(reserved, ch)) {      /* keep it encoded */\r
+               ap_proxy_c2hex(ch, &y[j]);\r
+               j += 2;\r
+               continue;\r
+           }\r
+       }\r
+/* recode it, if necessary */\r
+       if (!apr_isalnum(ch) && !strchr(allowed, ch)) {\r
+           ap_proxy_c2hex(ch, &y[j]);\r
+           j += 2;\r
+       }\r
+       else\r
+           y[j] = ch;\r
+    }\r
+    y[j] = '\0';\r
+    return y;\r
+}\r
+\r
+/*\r
+ * Parses network-location.\r
+ *    urlp           on input the URL; on output the path, after the leading /\r
+ *    user           NULL if no user/password permitted\r
+ *    password       holder for password\r
+ *    host           holder for host\r
+ *    port           port number; only set if one is supplied.\r
+ *\r
+ * Returns an error string.\r
+ */\r
+PROXY_DECLARE(char *)\r
+     ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp,\r
+                       char **passwordp, char **hostp, apr_port_t *port)\r
+{\r
+    char *addr, *scope_id, *strp, *host, *url = *urlp;\r
+    char *user = NULL, *password = NULL;\r
+    apr_port_t tmp_port;\r
+    apr_status_t rv;\r
+\r
+    if (url[0] != '/' || url[1] != '/')\r
+       return "Malformed URL";\r
+    host = url + 2;\r
+    url = strchr(host, '/');\r
+    if (url == NULL)\r
+       url = "";\r
+    else\r
+       *(url++) = '\0';        /* skip seperating '/' */\r
+\r
+    /* find _last_ '@' since it might occur in user/password part */\r
+    strp = strrchr(host, '@');\r
+\r
+    if (strp != NULL) {\r
+       *strp = '\0';\r
+       user = host;\r
+       host = strp + 1;\r
+\r
+/* find password */\r
+       strp = strchr(user, ':');\r
+       if (strp != NULL) {\r
+           *strp = '\0';\r
+           password = ap_proxy_canonenc(p, strp + 1, strlen(strp + 1), enc_user, 1);\r
+           if (password == NULL)\r
+               return "Bad %-escape in URL (password)";\r
+       }\r
+\r
+       user = ap_proxy_canonenc(p, user, strlen(user), enc_user, 1);\r
+       if (user == NULL)\r
+           return "Bad %-escape in URL (username)";\r
+    }\r
+    if (userp != NULL) {\r
+       *userp = user;\r
+    }\r
+    if (passwordp != NULL) {\r
+       *passwordp = password;\r
+    }\r
+\r
+    /* Parse the host string to separate host portion from optional port.\r
+     * Perform range checking on port.\r
+     */\r
+    rv = apr_parse_addr_port(&addr, &scope_id, &tmp_port, host, p);\r
+    if (rv != APR_SUCCESS || addr == NULL || scope_id != NULL) {\r
+        return "Invalid host/port";\r
+    }\r
+    if (tmp_port != 0) { /* only update caller's port if port was specified */\r
+        *port = tmp_port;\r
+    }\r
+\r
+    ap_str_tolower(addr); /* DNS names are case-insensitive */\r
+\r
+    *urlp = url;\r
+    *hostp = addr;\r
+\r
+    return NULL;\r
+}\r
+\r
+static const char * const lwday[7] =\r
+{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};\r
+\r
+/*\r
+ * If the date is a valid RFC 850 date or asctime() date, then it\r
+ * is converted to the RFC 1123 format, otherwise it is not modified.\r
+ * This routine is not very fast at doing conversions, as it uses\r
+ * sscanf and sprintf. However, if the date is already correctly\r
+ * formatted, then it exits very quickly.\r
+ */\r
+PROXY_DECLARE(const char *)\r
+     ap_proxy_date_canon(apr_pool_t *p, const char *x1)\r
+{\r
+    char *x = apr_pstrdup(p, x1);\r
+    int wk, mday, year, hour, min, sec, mon;\r
+    char *q, month[4], zone[4], week[4];\r
+\r
+    q = strchr(x, ',');\r
+    /* check for RFC 850 date */\r
+    if (q != NULL && q - x > 3 && q[1] == ' ') {\r
+       *q = '\0';\r
+       for (wk = 0; wk < 7; wk++)\r
+           if (strcmp(x, lwday[wk]) == 0)\r
+               break;\r
+       *q = ',';\r
+       if (wk == 7)\r
+           return x;           /* not a valid date */\r
+       if (q[4] != '-' || q[8] != '-' || q[11] != ' ' || q[14] != ':' ||\r
+           q[17] != ':' || strcmp(&q[20], " GMT") != 0)\r
+           return x;\r
+       if (sscanf(q + 2, "%u-%3s-%u %u:%u:%u %3s", &mday, month, &year,\r
+                  &hour, &min, &sec, zone) != 7)\r
+           return x;\r
+       if (year < 70)\r
+           year += 2000;\r
+       else\r
+           year += 1900;\r
+    }\r
+    else {\r
+/* check for acstime() date */\r
+       if (x[3] != ' ' || x[7] != ' ' || x[10] != ' ' || x[13] != ':' ||\r
+           x[16] != ':' || x[19] != ' ' || x[24] != '\0')\r
+           return x;\r
+       if (sscanf(x, "%3s %3s %u %u:%u:%u %u", week, month, &mday, &hour,\r
+                  &min, &sec, &year) != 7)\r
+           return x;\r
+       for (wk = 0; wk < 7; wk++)\r
+           if (strcmp(week, apr_day_snames[wk]) == 0)\r
+               break;\r
+       if (wk == 7)\r
+           return x;\r
+    }\r
+\r
+/* check date */\r
+    for (mon = 0; mon < 12; mon++)\r
+       if (strcmp(month, apr_month_snames[mon]) == 0)\r
+           break;\r
+    if (mon == 12)\r
+       return x;\r
+\r
+    q = apr_palloc(p, 30);\r
+    apr_snprintf(q, 30, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", apr_day_snames[wk],\r
+       mday, apr_month_snames[mon], year, hour, min, sec);\r
+    return q;\r
+}\r
+\r
+PROXY_DECLARE(request_rec *)ap_proxy_make_fake_req(conn_rec *c, request_rec *r)\r
+{\r
+    request_rec *rp = apr_pcalloc(c->pool, sizeof(*r));\r
+\r
+    rp->pool            = c->pool;\r
+    rp->status          = HTTP_OK;\r
+\r
+    rp->headers_in      = apr_table_make(c->pool, 50);\r
+    rp->subprocess_env  = apr_table_make(c->pool, 50);\r
+    rp->headers_out     = apr_table_make(c->pool, 12);\r
+    rp->err_headers_out = apr_table_make(c->pool, 5);\r
+    rp->notes           = apr_table_make(c->pool, 5);\r
+\r
+    rp->server = r->server;\r
+    rp->proxyreq = r->proxyreq;\r
+    rp->request_time = r->request_time;\r
+    rp->connection      = c;\r
+    rp->output_filters  = c->output_filters;\r
+    rp->input_filters   = c->input_filters;\r
+    rp->proto_output_filters  = c->output_filters;\r
+    rp->proto_input_filters   = c->input_filters;\r
+\r
+    rp->request_config  = ap_create_request_config(c->pool);\r
+    proxy_run_create_req(r, rp);\r
+\r
+    return rp;\r
+}\r
+\r
+\r
+/*\r
+ * list is a comma-separated list of case-insensitive tokens, with\r
+ * optional whitespace around the tokens.\r
+ * The return returns 1 if the token val is found in the list, or 0\r
+ * otherwise.\r
+ */\r
+PROXY_DECLARE(int) ap_proxy_liststr(const char *list, const char *val)\r
+{\r
+    int len, i;\r
+    const char *p;\r
+\r
+    len = strlen(val);\r
+\r
+    while (list != NULL) {\r
+       p = ap_strchr_c(list, ',');\r
+       if (p != NULL) {\r
+           i = p - list;\r
+           do\r
+               p++;\r
+           while (apr_isspace(*p));\r
+       }\r
+       else\r
+           i = strlen(list);\r
+\r
+       while (i > 0 && apr_isspace(list[i - 1]))\r
+           i--;\r
+       if (i == len && strncasecmp(list, val, len) == 0)\r
+           return 1;\r
+       list = p;\r
+    }\r
+    return 0;\r
+}\r
+\r
+/*\r
+ * list is a comma-separated list of case-insensitive tokens, with\r
+ * optional whitespace around the tokens.\r
+ * if val appears on the list of tokens, it is removed from the list,\r
+ * and the new list is returned.\r
+ */\r
+PROXY_DECLARE(char *)ap_proxy_removestr(apr_pool_t *pool, const char *list, const char *val)\r
+{\r
+    int len, i;\r
+    const char *p;\r
+    char *new = NULL;\r
+\r
+    len = strlen(val);\r
+\r
+    while (list != NULL) {\r
+       p = ap_strchr_c(list, ',');\r
+       if (p != NULL) {\r
+           i = p - list;\r
+           do\r
+               p++;\r
+           while (apr_isspace(*p));\r
+       }\r
+       else\r
+           i = strlen(list);\r
+\r
+       while (i > 0 && apr_isspace(list[i - 1]))\r
+           i--;\r
+       if (i == len && strncasecmp(list, val, len) == 0) {\r
+           /* do nothing */\r
+       }\r
+       else {\r
+           if (new)\r
+               new = apr_pstrcat(pool, new, ",", apr_pstrndup(pool, list, i), NULL);\r
+           else\r
+               new = apr_pstrndup(pool, list, i);\r
+       }\r
+       list = p;\r
+    }\r
+    return new;\r
+}\r
+\r
+/*\r
+ * Converts 8 hex digits to a time integer\r
+ */\r
+PROXY_DECLARE(int) ap_proxy_hex2sec(const char *x)\r
+{\r
+    int i, ch;\r
+    unsigned int j;\r
+\r
+    for (i = 0, j = 0; i < 8; i++) {\r
+       ch = x[i];\r
+       j <<= 4;\r
+       if (apr_isdigit(ch))\r
+           j |= ch - '0';\r
+       else if (apr_isupper(ch))\r
+           j |= ch - ('A' - 10);\r
+       else\r
+           j |= ch - ('a' - 10);\r
+    }\r
+    if (j == 0xffffffff)\r
+       return -1;              /* so that it works with 8-byte ints */\r
+    else\r
+       return j;\r
+}\r
+\r
+/*\r
+ * Converts a time integer to 8 hex digits\r
+ */\r
+PROXY_DECLARE(void) ap_proxy_sec2hex(int t, char *y)\r
+{\r
+    int i, ch;\r
+    unsigned int j = t;\r
+\r
+    for (i = 7; i >= 0; i--) {\r
+       ch = j & 0xF;\r
+       j >>= 4;\r
+       if (ch >= 10)\r
+           y[i] = ch + ('A' - 10);\r
+       else\r
+           y[i] = ch + '0';\r
+    }\r
+    y[8] = '\0';\r
+}\r
+\r
+PROXY_DECLARE(int) ap_proxyerror(request_rec *r, int statuscode, const char *message)\r
+{\r
+    apr_table_setn(r->notes, "error-notes",\r
+       apr_pstrcat(r->pool, \r
+               "The proxy server could not handle the request "\r
+               "<em><a href=\"", ap_escape_uri(r->pool, r->uri),\r
+               "\">", ap_escape_html(r->pool, r->method),\r
+               "&nbsp;", \r
+               ap_escape_html(r->pool, r->uri), "</a></em>.<p>\n"\r
+               "Reason: <strong>",\r
+               ap_escape_html(r->pool, message), \r
+               "</strong></p>", NULL));\r
+\r
+    /* Allow "error-notes" string to be printed by ap_send_error_response() */\r
+    apr_table_setn(r->notes, "verbose-error-to", apr_pstrdup(r->pool, "*"));\r
+\r
+    r->status_line = apr_psprintf(r->pool, "%3.3u Proxy Error", statuscode);\r
+    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,\r
+                        "proxy: %s returned by %s", message, r->uri);\r
+    return statuscode;\r
+}\r
+\r
+static const char *\r
+     proxy_get_host_of_request(request_rec *r)\r
+{\r
+    char *url, *user = NULL, *password = NULL, *err, *host;\r
+    apr_port_t port;\r
+\r
+    if (r->hostname != NULL)\r
+       return r->hostname;\r
+\r
+    /* Set url to the first char after "scheme://" */\r
+    if ((url = strchr(r->uri, ':')) == NULL\r
+       || url[1] != '/' || url[2] != '/')\r
+       return NULL;\r
+\r
+    url = apr_pstrdup(r->pool, &url[1]);       /* make it point to "//", which is what proxy_canon_netloc expects */\r
+\r
+    err = ap_proxy_canon_netloc(r->pool, &url, &user, &password, &host, &port);\r
+\r
+    if (err != NULL)\r
+       ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,\r
+                    "%s", err);\r
+\r
+    r->hostname = host;\r
+\r
+    return host;               /* ought to return the port, too */\r
+}\r
+\r
+/* Return TRUE if addr represents an IP address (or an IP network address) */\r
+PROXY_DECLARE(int) ap_proxy_is_ipaddr(struct dirconn_entry *This, apr_pool_t *p)\r
+{\r
+    const char *addr = This->name;\r
+    long ip_addr[4];\r
+    int i, quads;\r
+    long bits;\r
+\r
+    /* if the address is given with an explicit netmask, use that */\r
+    /* Due to a deficiency in apr_inet_addr(), it is impossible to parse */\r
+    /* "partial" addresses (with less than 4 quads) correctly, i.e.  */\r
+    /* 192.168.123 is parsed as 192.168.0.123, which is not what I want. */\r
+    /* I therefore have to parse the IP address manually: */\r
+    /*if (proxy_readmask(This->name, &This->addr.s_addr, &This->mask.s_addr) == 0) */\r
+    /* addr and mask were set by proxy_readmask() */\r
+    /*return 1; */\r
+\r
+    /* Parse IP addr manually, optionally allowing */\r
+    /* abbreviated net addresses like 192.168. */\r
+\r
+    /* Iterate over up to 4 (dotted) quads. */\r
+    for (quads = 0; quads < 4 && *addr != '\0'; ++quads) {\r
+       char *tmp;\r
+\r
+       if (*addr == '/' && quads > 0)  /* netmask starts here. */\r
+           break;\r
+\r
+       if (!apr_isdigit(*addr))\r
+           return 0;           /* no digit at start of quad */\r
+\r
+       ip_addr[quads] = strtol(addr, &tmp, 0);\r
+\r
+       if (tmp == addr)        /* expected a digit, found something else */\r
+           return 0;\r
+\r
+       if (ip_addr[quads] < 0 || ip_addr[quads] > 255) {\r
+           /* invalid octet */\r
+           return 0;\r
+       }\r
+\r
+       addr = tmp;\r
+\r
+       if (*addr == '.' && quads != 3)\r
+           ++addr;             /* after the 4th quad, a dot would be illegal */\r
+    }\r
+\r
+    for (This->addr.s_addr = 0, i = 0; i < quads; ++i)\r
+       This->addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));\r
+\r
+    if (addr[0] == '/' && apr_isdigit(addr[1])) {      /* net mask follows: */\r
+       char *tmp;\r
+\r
+       ++addr;\r
+\r
+       bits = strtol(addr, &tmp, 0);\r
+\r
+       if (tmp == addr)        /* expected a digit, found something else */\r
+           return 0;\r
+\r
+       addr = tmp;\r
+\r
+       if (bits < 0 || bits > 32)      /* netmask must be between 0 and 32 */\r
+           return 0;\r
+\r
+    }\r
+    else {\r
+       /* Determine (i.e., "guess") netmask by counting the */\r
+       /* number of trailing .0's; reduce #quads appropriately */\r
+       /* (so that 192.168.0.0 is equivalent to 192.168.)        */\r
+       while (quads > 0 && ip_addr[quads - 1] == 0)\r
+           --quads;\r
+\r
+       /* "IP Address should be given in dotted-quad form, optionally followed by a netmask (e.g., 192.168.111.0/24)"; */\r
+       if (quads < 1)\r
+           return 0;\r
+\r
+       /* every zero-byte counts as 8 zero-bits */\r
+       bits = 8 * quads;\r
+\r
+       if (bits != 32)         /* no warning for fully qualified IP address */\r
+            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,\r
+             "Warning: NetMask not supplied with IP-Addr; guessing: %s/%ld\n",\r
+                inet_ntoa(This->addr), bits);\r
+    }\r
+\r
+    This->mask.s_addr = htonl(APR_INADDR_NONE << (32 - bits));\r
+\r
+    if (*addr == '\0' && (This->addr.s_addr & ~This->mask.s_addr) != 0) {\r
+        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,\r
+           "Warning: NetMask and IP-Addr disagree in %s/%ld\n",\r
+               inet_ntoa(This->addr), bits);\r
+       This->addr.s_addr &= This->mask.s_addr;\r
+        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,\r
+           "         Set to %s/%ld\n",\r
+               inet_ntoa(This->addr), bits);\r
+    }\r
+\r
+    if (*addr == '\0') {\r
+       This->matcher = proxy_match_ipaddr;\r
+       return 1;\r
+    }\r
+    else\r
+       return (*addr == '\0'); /* okay iff we've parsed the whole string */\r
+}\r
+\r
+/* Return TRUE if addr represents an IP address (or an IP network address) */\r
+static int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r)\r
+{\r
+    int i, ip_addr[4];\r
+    struct in_addr addr, *ip;\r
+    const char *host = proxy_get_host_of_request(r);\r
+\r
+    if (host == NULL)   /* oops! */\r
+       return 0;\r
+\r
+    memset(&addr, '\0', sizeof addr);\r
+    memset(ip_addr, '\0', sizeof ip_addr);\r
+\r
+    if (4 == sscanf(host, "%d.%d.%d.%d", &ip_addr[0], &ip_addr[1], &ip_addr[2], &ip_addr[3])) {\r
+       for (addr.s_addr = 0, i = 0; i < 4; ++i)\r
+           addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));\r
+\r
+       if (This->addr.s_addr == (addr.s_addr & This->mask.s_addr)) {\r
+#if DEBUGGING\r
+        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,\r
+                         "1)IP-Match: %s[%s] <-> ", host, inet_ntoa(addr));\r
+        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,\r
+                         "%s/", inet_ntoa(This->addr));\r
+        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,\r
+                         "%s", inet_ntoa(This->mask));\r
+#endif\r
+           return 1;\r
+       }\r
+#if DEBUGGING\r
+       else {\r
+        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,\r
+                         "1)IP-NoMatch: %s[%s] <-> ", host, inet_ntoa(addr));\r
+        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,\r
+                         "%s/", inet_ntoa(This->addr));\r
+        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,\r
+                         "%s", inet_ntoa(This->mask));\r
+       }\r
+#endif\r
+    }\r
+    else {\r
+       struct apr_sockaddr_t *reqaddr;\r
+\r
+        if (apr_sockaddr_info_get(&reqaddr, host, APR_UNSPEC, 0, 0, r->pool)\r
+           != APR_SUCCESS) {\r
+#if DEBUGGING\r
+           ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,\r
+                        "2)IP-NoMatch: hostname=%s msg=Host not found", \r
+                        host);\r
+#endif\r
+           return 0;\r
+       }\r
+\r
+       /* Try to deal with multiple IP addr's for a host */\r
+       /* FIXME: This needs to be able to deal with IPv6 */\r
+       while (reqaddr) {\r
+           ip = (struct in_addr *) reqaddr->ipaddr_ptr;\r
+           if (This->addr.s_addr == (ip->s_addr & This->mask.s_addr)) {\r
+#if DEBUGGING\r
+               ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,\r
+                            "3)IP-Match: %s[%s] <-> ", host, \r
+                            inet_ntoa(*ip));\r
+               ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,\r
+                            "%s/", inet_ntoa(This->addr));\r
+               ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,\r
+                            "%s", inet_ntoa(This->mask));\r
+#endif\r
+               return 1;\r
+           }\r
+#if DEBUGGING\r
+           else {\r
+                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,\r
+                            "3)IP-NoMatch: %s[%s] <-> ", host, \r
+                            inet_ntoa(*ip));\r
+                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,\r
+                            "%s/", inet_ntoa(This->addr));\r
+                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,\r
+                            "%s", inet_ntoa(This->mask));\r
+           }\r
+#endif\r
+           reqaddr = reqaddr->next;\r
+       }\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+/* Return TRUE if addr represents a domain name */\r
+PROXY_DECLARE(int) ap_proxy_is_domainname(struct dirconn_entry *This, apr_pool_t *p)\r
+{\r
+    char *addr = This->name;\r
+    int i;\r
+\r
+    /* Domain name must start with a '.' */\r
+    if (addr[0] != '.')\r
+        return 0;\r
+\r
+    /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */\r
+    for (i = 0; apr_isalnum(addr[i]) || addr[i] == '-' || addr[i] == '.'; ++i)\r
+        continue;\r
+\r
+#if 0\r
+    if (addr[i] == ':') {\r
+    ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,\r
+                     "@@@@ handle optional port in proxy_is_domainname()");\r
+       /* @@@@ handle optional port */\r
+    }\r
+#endif\r
+\r
+    if (addr[i] != '\0')\r
+        return 0;\r
+\r
+    /* Strip trailing dots */\r
+    for (i = strlen(addr) - 1; i > 0 && addr[i] == '.'; --i)\r
+        addr[i] = '\0';\r
+\r
+    This->matcher = proxy_match_domainname;\r
+    return 1;\r
+}\r
+\r
+/* Return TRUE if host "host" is in domain "domain" */\r
+static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r)\r
+{\r
+    const char *host = proxy_get_host_of_request(r);\r
+    int d_len = strlen(This->name), h_len;\r
+\r
+    if (host == NULL)          /* some error was logged already */\r
+        return 0;\r
+\r
+    h_len = strlen(host);\r
+\r
+    /* @@@ do this within the setup? */\r
+    /* Ignore trailing dots in domain comparison: */\r
+    while (d_len > 0 && This->name[d_len - 1] == '.')\r
+        --d_len;\r
+    while (h_len > 0 && host[h_len - 1] == '.')\r
+        --h_len;\r
+    return h_len > d_len\r
+        && strncasecmp(&host[h_len - d_len], This->name, d_len) == 0;\r
+}\r
+\r
+/* Return TRUE if host represents a host name */\r
+PROXY_DECLARE(int) ap_proxy_is_hostname(struct dirconn_entry *This, apr_pool_t *p)\r
+{\r
+    struct apr_sockaddr_t *addr;\r
+    char *host = This->name;\r
+    int i;\r
+\r
+    /* Host names must not start with a '.' */\r
+    if (host[0] == '.')\r
+        return 0;\r
+\r
+    /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */\r
+    for (i = 0; apr_isalnum(host[i]) || host[i] == '-' || host[i] == '.'; ++i);\r
+\r
+    if (host[i] != '\0' || apr_sockaddr_info_get(&addr, host, APR_UNSPEC, 0, 0, p) != APR_SUCCESS)\r
+        return 0;\r
+    \r
+    This->hostaddr = addr;\r
+\r
+    /* Strip trailing dots */\r
+    for (i = strlen(host) - 1; i > 0 && host[i] == '.'; --i)\r
+        host[i] = '\0';\r
+\r
+    This->matcher = proxy_match_hostname;\r
+    return 1;\r
+}\r
+\r
+/* Return TRUE if host "host" is equal to host2 "host2" */\r
+static int proxy_match_hostname(struct dirconn_entry *This, request_rec *r)\r
+{\r
+    char *host = This->name;\r
+    const char *host2 = proxy_get_host_of_request(r);\r
+    int h2_len;\r
+    int h1_len;\r
+\r
+    if (host == NULL || host2 == NULL)\r
+        return 0; /* oops! */\r
+\r
+    h2_len = strlen(host2);\r
+    h1_len = strlen(host);\r
+\r
+#if 0\r
+    struct apr_sockaddr_t *addr = *This->hostaddr;\r
+\r
+    /* Try to deal with multiple IP addr's for a host */\r
+    while (addr) {\r
+        if (addr->ipaddr_ptr == ? ? ? ? ? ? ? ? ? ? ? ? ?)\r
+            return 1;\r
+        addr = addr->next;\r
+    }\r
+#endif\r
+\r
+    /* Ignore trailing dots in host2 comparison: */\r
+    while (h2_len > 0 && host2[h2_len - 1] == '.')\r
+        --h2_len;\r
+    while (h1_len > 0 && host[h1_len - 1] == '.')\r
+        --h1_len;\r
+    return h1_len == h2_len\r
+        && strncasecmp(host, host2, h1_len) == 0;\r
+}\r
+\r
+/* Return TRUE if addr is to be matched as a word */\r
+PROXY_DECLARE(int) ap_proxy_is_word(struct dirconn_entry *This, apr_pool_t *p)\r
+{\r
+    This->matcher = proxy_match_word;\r
+    return 1;\r
+}\r
+\r
+/* Return TRUE if string "str2" occurs literally in "str1" */\r
+static int proxy_match_word(struct dirconn_entry *This, request_rec *r)\r
+{\r
+    const char *host = proxy_get_host_of_request(r);\r
+    return host != NULL && ap_strstr_c(host, This->name) != NULL;\r
+}\r
+\r
+/* checks whether a host in uri_addr matches proxyblock */\r
+PROXY_DECLARE(int) ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf, \r
+                             apr_sockaddr_t *uri_addr)\r
+{\r
+    int j;\r
+    apr_sockaddr_t * src_uri_addr = uri_addr;\r
+    /* XXX FIXME: conf->noproxies->elts is part of an opaque structure */\r
+    for (j = 0; j < conf->noproxies->nelts; j++) {\r
+        struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts;\r
+        struct apr_sockaddr_t *conf_addr = npent[j].addr;\r
+        uri_addr = src_uri_addr;\r
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,\r
+                     "proxy: checking remote machine [%s] against [%s]", uri_addr->hostname, npent[j].name);\r
+        if ((npent[j].name && ap_strstr_c(uri_addr->hostname, npent[j].name))\r
+            || npent[j].name[0] == '*') {\r
+            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,\r
+                         "proxy: connect to remote machine %s blocked: name %s matched", uri_addr->hostname, npent[j].name);\r
+            return HTTP_FORBIDDEN;\r
+        }\r
+        while (conf_addr) {\r
+            while (uri_addr) {\r
+                char *conf_ip;\r
+                char *uri_ip;\r
+                apr_sockaddr_ip_get(&conf_ip, conf_addr);\r
+                apr_sockaddr_ip_get(&uri_ip, uri_addr);\r
+                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,\r
+                             "proxy: ProxyBlock comparing %s and %s", conf_ip, uri_ip);\r
+                if (!apr_strnatcasecmp(conf_ip, uri_ip)) {\r
+                    ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,\r
+                                 "proxy: connect to remote machine %s blocked: IP %s matched", uri_addr->hostname, conf_ip);\r
+                    return HTTP_FORBIDDEN;\r
+                }\r
+                uri_addr = uri_addr->next;\r
+            }\r
+            conf_addr = conf_addr->next;\r
+        }\r
+    }\r
+    return OK;\r
+}\r
+\r
+/* set up the minimal filter set */\r
+PROXY_DECLARE(int) ap_proxy_pre_http_request(conn_rec *c, request_rec *r)\r
+{\r
+    ap_add_input_filter("HTTP_IN", NULL, r, c);\r
+    return OK;\r
+}\r
+\r
+/* converts a series of buckets into a string \r
+ * XXX: BillS says this function performs essentially the same function as \r
+ * ap_rgetline() in protocol.c. Deprecate this function and use ap_rgetline() \r
+ * instead? I think ap_proxy_string_read() will not work properly on non ASCII\r
+ * (EBCDIC) machines either.\r
+ */\r
+PROXY_DECLARE(apr_status_t) ap_proxy_string_read(conn_rec *c, apr_bucket_brigade *bb,\r
+                                                 char *buff, apr_size_t bufflen, int *eos)\r
+{\r
+    apr_bucket *e;\r
+    apr_status_t rv;\r
+    char *pos = buff;\r
+    char *response;\r
+    int found = 0;\r
+    apr_size_t len;\r
+\r
+    /* start with an empty string */\r
+    buff[0] = 0;\r
+    *eos = 0;\r
+\r
+    /* loop through each brigade */\r
+    while (!found) {\r
+        /* get brigade from network one line at a time */\r
+        if (APR_SUCCESS != (rv = ap_get_brigade(c->input_filters, bb, \r
+                                                AP_MODE_GETLINE,\r
+                                                APR_BLOCK_READ,\r
+                                                0))) {\r
+            return rv;\r
+        }\r
+        /* loop through each bucket */\r
+        while (!found) {\r
+            if (*eos || APR_BRIGADE_EMPTY(bb)) {\r
+                /* The connection aborted or timed out */\r
+                return APR_ECONNABORTED;\r
+            }\r
+            e = APR_BRIGADE_FIRST(bb);\r
+            if (APR_BUCKET_IS_EOS(e)) {\r
+                *eos = 1;\r
+            }\r
+            else {\r
+                if (APR_SUCCESS != apr_bucket_read(e, (const char **)&response, &len, APR_BLOCK_READ)) {\r
+                    return rv;\r
+                }\r
+                /* is string LF terminated? \r
+                 * XXX: This check can be made more efficient by simply checking \r
+                 * if the last character in the 'response' buffer is an ASCII_LF.\r
+                 * See ap_rgetline() for an example.\r
+                 */\r
+                if (memchr(response, APR_ASCII_LF, len)) {\r
+                    found = 1;\r
+                }\r
+                /* concat strings until buff is full - then throw the data away */\r
+                if (len > ((bufflen-1)-(pos-buff))) {\r
+                    len = (bufflen-1)-(pos-buff);\r
+                }\r
+                if (len > 0) {\r
+                    pos = apr_cpystrn(pos, response, len);\r
+                }\r
+            }\r
+            APR_BUCKET_REMOVE(e);\r
+            apr_bucket_destroy(e);\r
+        }\r
+    }\r
+\r
+    return APR_SUCCESS;\r
+}\r
+\r
+/* unmerge an element in the table */\r
+PROXY_DECLARE(void) ap_proxy_table_unmerge(apr_pool_t *p, apr_table_t *t, char *key)\r
+{\r
+    apr_off_t offset = 0;\r
+    apr_off_t count = 0;\r
+    char *value = NULL;\r
+\r
+    /* get the value to unmerge */\r
+    const char *initial = apr_table_get(t, key);\r
+    if (!initial) {\r
+        return;\r
+    }\r
+    value = apr_pstrdup(p, initial);\r
+\r
+    /* remove the value from the headers */\r
+    apr_table_unset(t, key);\r
+\r
+    /* find each comma */\r
+    while (value[count]) {\r
+        if (value[count] == ',') {\r
+            value[count] = 0;\r
+            apr_table_add(t, key, value + offset);\r
+            offset = count + 1;\r
+        }\r
+        count++;\r
+    }\r
+    apr_table_add(t, key, value + offset);\r
+}\r
+\r
+PROXY_DECLARE(proxy_balancer *) ap_proxy_get_balancer(apr_pool_t *p,\r
+                                                      proxy_server_conf *conf,\r
+                                                      const char *url)\r
+{\r
+    proxy_balancer *balancer;\r
+    char *c, *uri = apr_pstrdup(p, url);\r
+    int i;\r
+    \r
+    c = strchr(uri, ':');   \r
+    if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')\r
+       return NULL;\r
+    /* remove path from uri */\r
+    if ((c = strchr(c + 3, '/')))\r
+        *c = '\0';\r
+    balancer = (proxy_balancer *)conf->balancers->elts;\r
+    for (i = 0; i < conf->balancers->nelts; i++) {\r
+        if (strcasecmp(balancer->name, uri) == 0)\r
+            return balancer;\r
+        balancer++;\r
+    }\r
+    return NULL;\r
+}\r
+\r
+PROXY_DECLARE(const char *) ap_proxy_add_balancer(proxy_balancer **balancer,\r
+                                                  apr_pool_t *p,\r
+                                                  proxy_server_conf *conf,\r
+                                                  const char *url)\r
+{\r
+    char *c, *q, *uri = apr_pstrdup(p, url);\r
+\r
+    c = strchr(uri, ':');   \r
+    if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')\r
+       return "Bad syntax for a balancer name";\r
+    /* remove path from uri */\r
+    if ((q = strchr(c + 3, '/')))\r
+        *q = '\0';\r
+\r
+    ap_str_tolower(uri);\r
+    *balancer = apr_array_push(conf->balancers);\r
+    memset(*balancer, 0, sizeof(proxy_balancer));\r
+\r
+    (*balancer)->name = uri;\r
+    (*balancer)->workers = apr_array_make(p, 5, sizeof(proxy_worker));\r
+    /* XXX Is this a right place to create mutex */\r
+#if APR_HAS_THREADS\r
+    if (apr_thread_mutex_create(&((*balancer)->mutex),\r
+                APR_THREAD_MUTEX_DEFAULT, p) != APR_SUCCESS) {\r
+        /* XXX: Do we need to log something here */\r
+        return "can not create thread mutex";\r
+    }\r
+#endif\r
+\r
+    return NULL;\r
+}\r
+\r
+PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,\r
+                                                  proxy_server_conf *conf,\r
+                                                  const char *url)\r
+{\r
+    proxy_worker *worker;\r
+    char *c, *uri = apr_pstrdup(p, url);\r
+    int i;\r
+    \r
+    c = strchr(uri, ':');   \r
+    if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')\r
+       return NULL;\r
+    /* remove path from uri */\r
+    if ((c = strchr(c + 3, '/')))\r
+        *c = '\0';\r
+\r
+    worker = (proxy_worker *)conf->workers->elts;\r
+    for (i = 0; i < conf->workers->nelts; i++) {\r
+        if (strcasecmp(worker->name, uri) == 0) {\r
+            return worker;\r
+        }\r
+        worker++;\r
+    }\r
+    return NULL;\r
+}\r
+\r
+#if APR_HAS_THREADS\r
+static apr_status_t conn_pool_cleanup(void *theworker)\r
+{\r
+    proxy_worker *worker = (proxy_worker *)theworker;\r
+    if (worker->cp->res) {\r
+        worker->cp->pool = NULL;\r
+        apr_reslist_destroy(worker->cp->res);\r
+    }\r
+    return APR_SUCCESS;\r
+}\r
+#endif\r
+\r
+static void init_conn_pool(apr_pool_t *p, proxy_worker *worker)\r
+{\r
+    apr_pool_t *pool;\r
+    proxy_conn_pool *cp;\r
+    \r
+    /* Create a connection pool's subpool. \r
+     * This pool is used for connection recycling.\r
+     * Once the worker is added it is never removed but\r
+     * it can be disabled.\r
+     */\r
+    apr_pool_create(&pool, p);\r
+    /* Alloc from the same pool as worker.\r
+     * proxy_conn_pool is permanently attached to the worker. \r
+     */\r
+    cp = (proxy_conn_pool *)apr_pcalloc(p, sizeof(proxy_conn_pool));\r
+    cp->pool = pool;    \r
+    worker->cp = cp;\r
+}\r
+\r
+PROXY_DECLARE(const char *) ap_proxy_add_worker(proxy_worker **worker,\r
+                                                apr_pool_t *p,\r
+                                                proxy_server_conf *conf,\r
+                                                const char *url)\r
+{\r
+    char *c, *q, *uri = apr_pstrdup(p, url);\r
+    int port;\r
+    \r
+    c = strchr(uri, ':');   \r
+    if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')\r
+       return "Bad syntax for a remote proxy server";\r
+    /* remove path from uri */\r
+    if ((q = strchr(c + 3, '/')))\r
+        *q = '\0';\r
+\r
+    q = strchr(c + 3, ':');\r
+    if (q != NULL) {\r
+        if (sscanf(q + 1, "%u", &port) != 1 || port > 65535) {\r
+            return "Bad syntax for a remote proxy server (bad port number)";\r
+        }\r
+    }\r
+    else\r
+        port = -1;\r
+    ap_str_tolower(uri);\r
+    *worker = apr_array_push(conf->workers);\r
+    memset(*worker, 0, sizeof(proxy_worker));\r
+    (*worker)->name = apr_pstrdup(p, uri);\r
+    *c = '\0';\r
+    (*worker)->scheme = uri;\r
+    (*worker)->hostname = c + 3;\r
+\r
+    if (port == -1)\r
+        port = apr_uri_port_of_scheme((*worker)->scheme);\r
+    (*worker)->port = port;\r
+    (*worker)->id   = proxy_lb_workers;\r
+    /* Increase the total worker count */\r
+    proxy_lb_workers++;\r
+    init_conn_pool(p, *worker);\r
+\r
+    return NULL;\r
+}\r
+\r
+PROXY_DECLARE(proxy_worker *) ap_proxy_create_worker(apr_pool_t *p)\r
+{\r
+\r
+    proxy_worker *worker;\r
+    worker = (proxy_worker *)apr_pcalloc(p, sizeof(proxy_worker));\r
+    worker->id = proxy_lb_workers;\r
+    /* Increase the total worker count */\r
+    proxy_lb_workers++;\r
+    init_conn_pool(p, worker);\r
+\r
+    return worker;\r
+}\r
+\r
+PROXY_DECLARE(void) \r
+ap_proxy_add_worker_to_balancer(apr_pool_t *pool, proxy_balancer *balancer,\r
+                                proxy_worker *worker)\r
+{\r
+    proxy_worker *runtime;\r
+\r
+    runtime = apr_array_push(balancer->workers);\r
+    memcpy(runtime, worker, sizeof(proxy_worker));\r
+    runtime->id = proxy_lb_workers;\r
+    /* Increase the total runtime count */\r
+    proxy_lb_workers++;\r
+\r
+}\r
+\r
+PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,\r
+                                        proxy_balancer **balancer,\r
+                                        request_rec *r,\r
+                                        proxy_server_conf *conf, char **url)\r
+{\r
+    int access_status;\r
+    \r
+    access_status = proxy_run_pre_request(worker, balancer, r, conf, url);\r
+    if (access_status == DECLINED && *balancer == NULL) {\r
+        *worker = ap_proxy_get_worker(r->pool, conf, *url);\r
+        if (*worker) {\r
+            *balancer = NULL;\r
+            access_status = OK;\r
+        }\r
+        else if (r->proxyreq == PROXYREQ_PROXY) {\r
+            if (conf->forward) {\r
+                *balancer = NULL;\r
+                *worker = conf->forward;\r
+                access_status = OK;\r
+            }\r
+        }\r
+    }\r
+    else if (access_status == DECLINED && balancer != NULL) {\r
+        /* All the workers are busy */\r
+        access_status = HTTP_SERVICE_UNAVAILABLE;\r
+    }\r
+    return access_status;\r
+}\r
+\r
+PROXY_DECLARE(int) ap_proxy_post_request(proxy_worker *worker,\r
+                                         proxy_balancer *balancer,\r
+                                         request_rec *r,\r
+                                         proxy_server_conf *conf)\r
+{\r
+    int access_status;\r
+    if (balancer)\r
+        access_status = proxy_run_post_request(worker, balancer, r, conf);\r
+    else { \r
+        \r
+\r
+        access_status = OK;\r
+    }\r
+\r
+    return access_status;\r
+}\r
+\r
+/* DEPRECATED */\r
+PROXY_DECLARE(int) ap_proxy_connect_to_backend(apr_socket_t **newsock,\r
+                                               const char *proxy_function,\r
+                                               apr_sockaddr_t *backend_addr,\r
+                                               const char *backend_name,\r
+                                               proxy_server_conf *conf,\r
+                                               server_rec *s,\r
+                                               apr_pool_t *p)\r
+{\r
+    apr_status_t rv;\r
+    int connected = 0;\r
+    int loglevel;\r
+    \r
+    while (backend_addr && !connected) {\r
+        if ((rv = apr_socket_create(newsock, backend_addr->family,\r
+                                    SOCK_STREAM, 0, p)) != APR_SUCCESS) {\r
+            loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;\r
+            ap_log_error(APLOG_MARK, loglevel, rv, s,\r
+                         "proxy: %s: error creating fam %d socket for target %s",\r
+                         proxy_function,\r
+                         backend_addr->family,\r
+                         backend_name);\r
+            /* this could be an IPv6 address from the DNS but the\r
+             * local machine won't give us an IPv6 socket; hopefully the\r
+             * DNS returned an additional address to try\r
+             */\r
+            backend_addr = backend_addr->next;\r
+            continue;\r
+        }\r
+\r
+#if !defined(TPF) && !defined(BEOS)\r
+        if (conf->recv_buffer_size > 0 &&\r
+            (rv = apr_socket_opt_set(*newsock, APR_SO_RCVBUF,\r
+                                     conf->recv_buffer_size))) {\r
+            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,\r
+                         "apr_socket_opt_set(SO_RCVBUF): Failed to set "\r
+                         "ProxyReceiveBufferSize, using default");\r
+        }\r
+#endif\r
+\r
+        /* Set a timeout on the socket */\r
+        if (conf->timeout_set == 1) {\r
+            apr_socket_timeout_set(*newsock, conf->timeout);\r
+        }\r
+        else {\r
+             apr_socket_timeout_set(*newsock, s->timeout);\r
+        }\r
+\r
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,\r
+                     "proxy: %s: fam %d socket created to connect to %s",\r
+                     proxy_function, backend_addr->family, backend_name);\r
+\r
+        /* make the connection out of the socket */\r
+        rv = apr_socket_connect(*newsock, backend_addr);\r
+\r
+        /* if an error occurred, loop round and try again */\r
+        if (rv != APR_SUCCESS) {\r
+            apr_socket_close(*newsock);\r
+            loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;\r
+            ap_log_error(APLOG_MARK, loglevel, rv, s,\r
+                         "proxy: %s: attempt to connect to %pI (%s) failed",\r
+                         proxy_function,\r
+                         backend_addr,\r
+                         backend_name);\r
+            backend_addr = backend_addr->next;\r
+            continue;\r
+        }\r
+        connected = 1;\r
+    }\r
+    return connected ? 0 : 1;\r
+}\r
+\r
+static apr_status_t connection_cleanup(void *theconn)\r
+{\r
+    proxy_conn_rec *conn = (proxy_conn_rec *)theconn;\r
+    proxy_worker *worker = conn->worker;\r
+    \r
+    /* If the connection pool is NULL the worker\r
+     * cleanup has been run. Just return.\r
+     */\r
+    if (!worker->cp)\r
+        return APR_SUCCESS;\r
+\r
+    /* deterimine if the connection need to be closed */\r
+    if (conn->close_on_recycle || conn->close) {\r
+        apr_pool_t *p = conn->pool;\r
+        apr_pool_clear(conn->pool);\r
+        memset(conn, 0, sizeof(proxy_conn_rec));\r
+        conn->pool = p;\r
+        conn->worker = worker;\r
+    }\r
+#if APR_HAS_THREADS\r
+    if (worker->hmax && worker->cp->res) {\r
+        apr_reslist_release(worker->cp->res, (void *)conn);\r
+    }\r
+    else\r
+#endif\r
+    {\r
+        worker->cp->conn = conn;\r
+    }\r
+\r
+    /* Allways return the SUCCESS */\r
+    return APR_SUCCESS;\r
+}\r
+\r
+/* reslist constructor */\r
+static apr_status_t connection_constructor(void **resource, void *params,\r
+                                           apr_pool_t *pool)\r
+{\r
+    apr_pool_t *ctx;\r
+    proxy_conn_rec *conn;\r
+    proxy_worker *worker = (proxy_worker *)params;\r
+    \r
+    /* Create the subpool for each connection\r
+     * This keeps the memory consumption constant\r
+     * when disconnecting from backend.\r
+     */\r
+    apr_pool_create(&ctx, pool);\r
+    conn = apr_pcalloc(pool, sizeof(proxy_conn_rec));\r
+\r
+    conn->pool   = ctx;\r
+    conn->worker = worker;\r
+    *resource = conn;\r
+\r
+    return APR_SUCCESS;\r
+}\r
+\r
+/* reslist destructor */\r
+static apr_status_t connection_destructor(void *resource, void *params,\r
+                                          apr_pool_t *pool)\r
+{\r
+    proxy_conn_rec *conn = (proxy_conn_rec *)resource;\r
+\r
+    /* Destroy the pool only if not called from reslist_destroy */    \r
+    if (conn->worker->cp->pool)\r
+        apr_pool_destroy(conn->pool);\r
+\r
+    return APR_SUCCESS;\r
+}\r
+\r
+PROXY_DECLARE(void) ap_proxy_initialize_worker_share(proxy_server_conf *conf,\r
+                                                     proxy_worker *worker)\r
+{\r
+#if PROXY_HAS_SCOREBOARD\r
+    lb_score *score = NULL;\r
+#else\r
+    void *score = NULL;\r
+#endif\r
+#if PROXY_HAS_SCOREBOARD\r
+        /* Get scoreboard slot */\r
+    if (ap_scoreboard_image) {\r
+        score = ap_get_scoreboard_lb(worker->id);\r
+       if (!score)\r
+           ap_log_perror(APLOG_MARK, APLOG_ERR, 0, conf->pool,\r
+                         "proxy: ap_get_scoreboard_lb(%d) failed for worker %s",\r
+                         worker->id, worker->name);\r
+    }\r
+#endif\r
+    if (!score)\r
+        score = apr_pcalloc(conf->pool, sizeof(proxy_worker_stat));\r
+    worker->s = (proxy_worker_stat *)score;\r
+    if (worker->route)\r
+        strcpy(worker->s->route, worker->route);\r
+    else\r
+       *worker->s->route = '\0';\r
+    if (worker->redirect)\r
+        strcpy(worker->s->redirect, worker->redirect);\r
+    else\r
+       *worker->s->redirect = '\0';\r
+}\r
+\r
+PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, server_rec *s)\r
+{\r
+    apr_status_t rv;\r
+\r
+#if APR_HAS_THREADS\r
+    int mpm_threads;\r
+\r
+    ap_mpm_query(AP_MPMQ_MAX_THREADS, &mpm_threads);\r
+    if (mpm_threads > 1) {\r
+        /* Set hard max to no more then mpm_threads */\r
+        if (worker->hmax == 0 || worker->hmax > mpm_threads)\r
+            worker->hmax = mpm_threads;\r
+        if (worker->smax == 0 || worker->smax > worker->hmax)\r
+            worker->smax = worker->hmax;\r
+        /* Set min to be lower then smax */\r
+        if (worker->min > worker->smax)\r
+            worker->min = worker->smax; \r
+    }\r
+    else {\r
+        /* This will supress the apr_reslist creation */\r
+        worker->min = worker->smax = worker->hmax = 0;\r
+    }\r
+    if (worker->hmax) {\r
+        rv = apr_reslist_create(&(worker->cp->res),\r
+                                worker->min, worker->smax,\r
+                                worker->hmax, worker->ttl,\r
+                                connection_constructor, connection_destructor,\r
+                                worker, worker->cp->pool);\r
+\r
+        apr_pool_cleanup_register(worker->cp->pool, (void *)worker,\r
+                                  conn_pool_cleanup,\r
+                                  apr_pool_cleanup_null);\r
+\r
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,\r
+                     "proxy: initialized worker %d for (%s) min=%d max=%d smax=%d",\r
+                    worker->id, worker->hostname, worker->min, worker->hmax, worker->smax);\r
+\r
+#if (APR_MAJOR_VERSION > 0)\r
+        /* Set the acquire timeout */\r
+        if (rv == APR_SUCCESS && worker->acquire_set)\r
+            apr_reslist_timeout_set(worker->cp->res, worker->acquire);\r
+#endif\r
+    }\r
+    else\r
+#endif\r
+    {\r
+        \r
+        rv = connection_constructor((void **)&(worker->cp->conn), worker, worker->cp->pool);\r
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,\r
+                     "proxy: initialized single connection worker %d for (%s)",\r
+                    worker->id, worker->hostname);\r
+    }\r
+    if (rv == APR_SUCCESS)\r
+        worker->s->status |= PROXY_WORKER_INITIALIZED;\r
+    /* Set default parameters */\r
+    if (!worker->retry)\r
+        worker->retry = apr_time_from_sec(PROXY_WORKER_DEFAULT_RETRY);\r
+    return rv;\r
+}\r
+\r
+PROXY_DECLARE(int) ap_proxy_retry_worker(const char *proxy_function,\r
+                                         proxy_worker *worker,\r
+                                         server_rec *s)\r
+{\r
+    if (worker->s->status & PROXY_WORKER_IN_ERROR) {\r
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,\r
+                    "proxy: %s: retrying the worker for (%s)",\r
+                     proxy_function, worker->hostname);\r
+        if (apr_time_now() > worker->s->error_time + worker->retry) {\r
+            ++worker->s->retries;\r
+            worker->s->status &= ~PROXY_WORKER_IN_ERROR;\r
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,\r
+                         "proxy: %s: worker for (%s) has been marked for retry",\r
+                         proxy_function, worker->hostname);\r
+            return OK;\r
+        }\r
+        else\r
+            return DECLINED;\r
+    }\r
+    else\r
+        return OK;\r
+}\r
+\r
+PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function,\r
+                                               proxy_conn_rec **conn,\r
+                                               proxy_worker *worker,\r
+                                               server_rec *s)\r
+{\r
+    apr_status_t rv;\r
+\r
+    if (!PROXY_WORKER_IS_USABLE(worker)) {\r
+        /* Retry the worker */\r
+        ap_proxy_retry_worker(proxy_function, worker, s);\r
+    \r
+        if (!PROXY_WORKER_IS_USABLE(worker)) {\r
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,\r
+                         "proxy: %s: disabled connection for (%s)",\r
+                         proxy_function, worker->hostname);\r
+            return HTTP_SERVICE_UNAVAILABLE;\r
+        }\r
+    }\r
+#if APR_HAS_THREADS\r
+    if (worker->hmax) {\r
+        rv = apr_reslist_acquire(worker->cp->res, (void **)conn);\r
+    }\r
+    else\r
+#endif\r
+    {\r
+        /* create the new connection if the previous was destroyed */\r
+        if (!worker->cp->conn)\r
+            connection_constructor((void **)conn, worker, worker->cp->pool);\r
+        else {\r
+            *conn = worker->cp->conn;\r
+            worker->cp->conn = NULL;\r
+        }\r
+        rv = APR_SUCCESS;\r
+    }\r
+\r
+    if (rv != APR_SUCCESS) {\r
+        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,\r
+                     "proxy: %s: failed to acquire connection for (%s)",\r
+                     proxy_function, worker->hostname);\r
+        return HTTP_SERVICE_UNAVAILABLE;\r
+    }\r
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,\r
+                 "proxy: %s: has acquired connection for (%s)",\r
+                 proxy_function, worker->hostname);\r
+\r
+    (*conn)->worker = worker;\r
+    (*conn)->close  = 0;\r
+    (*conn)->close_on_recycle = 0;\r
+\r
+    return OK;\r
+}\r
+\r
+PROXY_DECLARE(int) ap_proxy_release_connection(const char *proxy_function,\r
+                                               proxy_conn_rec *conn,\r
+                                               server_rec *s)\r
+{\r
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,\r
+                 "proxy: %s: has released connection for (%s)",\r
+                 proxy_function, conn->worker->hostname);\r
+    /* If there is a connection kill it's cleanup */\r
+    if (conn->connection) {\r
+        apr_pool_cleanup_kill(conn->connection->pool, conn, connection_cleanup);\r
+        conn->connection = NULL;\r
+    }\r
+    connection_cleanup(conn);\r
+\r
+    return OK;\r
+}\r
+\r
+PROXY_DECLARE(int)\r
+ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,\r
+                              proxy_server_conf *conf,\r
+                              proxy_worker *worker,\r
+                              proxy_conn_rec *conn,\r
+                              apr_uri_t *uri,\r
+                              char **url,\r
+                              const char *proxyname,\r
+                              apr_port_t proxyport,\r
+                              char *server_portstr,\r
+                              int server_portstr_size)\r
+{\r
+    int server_port;\r
+    apr_status_t err = APR_SUCCESS;\r
+    /*\r
+     * Break up the URL to determine the host to connect to\r
+     */\r
+\r
+    /* we break the URL into host, port, uri */\r
+    if (APR_SUCCESS != apr_uri_parse(p, *url, uri)) {\r
+        return ap_proxyerror(r, HTTP_BAD_REQUEST,\r
+                             apr_pstrcat(p,"URI cannot be parsed: ", *url,\r
+                                         NULL));\r
+    }\r
+    if (!uri->port) {\r
+        uri->port = apr_uri_port_of_scheme(uri->scheme);\r
+    }\r
+\r
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,\r
+                 "proxy: connecting %s to %s:%d", *url, uri->hostname,\r
+                 uri->port);\r
+\r
+    /* allocate these out of the specified connection pool \r
+     * The scheme handler decides if this is permanent or\r
+     * short living pool.\r
+     */\r
+    /* are we connecting directly, or via a proxy? */\r
+    if (!proxyname) {\r
+        *url = apr_pstrcat(p, uri->path, uri->query ? "?" : "",\r
+                           uri->query ? uri->query : "",\r
+                           uri->fragment ? "#" : "",\r
+                           uri->fragment ? uri->fragment : "", NULL);\r
+    }\r
+    if (!conn->hostname) {\r
+        if (proxyname) {\r
+            conn->hostname = apr_pstrdup(conn->pool, proxyname);\r
+            conn->port = proxyport;\r
+        } else {\r
+            conn->hostname = apr_pstrdup(conn->pool, uri->hostname);\r
+            conn->port = uri->port;\r
+        }\r
+    }\r
+    /* TODO: add address cache for forward proxies */\r
+    conn->addr = worker->cp->addr;\r
+    if (r->proxyreq == PROXYREQ_PROXY) {\r
+        err = apr_sockaddr_info_get(&(conn->addr),\r
+                                    conn->hostname, APR_UNSPEC,\r
+                                    conn->port, 0,\r
+                                    conn->pool);\r
+    }\r
+    else if (!worker->cp->addr) {\r
+        /* Worker can have the single constant backend adress.\r
+         * The single DNS lookup is used once per worker.\r
+        * If dynamic change is needed then set the addr to NULL\r
+        * inside dynamic config to force the lookup.\r
+        */\r
+        err = apr_sockaddr_info_get(&(worker->cp->addr),\r
+                                    conn->hostname, APR_UNSPEC,\r
+                                    conn->port, 0,\r
+                                    worker->cp->pool);\r
+        conn->addr = worker->cp->addr;\r
+    }\r
+    if (err != APR_SUCCESS) {\r
+        return ap_proxyerror(r, HTTP_BAD_GATEWAY,\r
+                             apr_pstrcat(p, "DNS lookup failure for: ",\r
+                                         conn->hostname, NULL));\r
+    }\r
+\r
+    /* Get the server port for the Via headers */\r
+    {\r
+        server_port = ap_get_server_port(r);\r
+        if (ap_is_default_port(server_port, r)) {\r
+            strcpy(server_portstr,"");\r
+        } else {\r
+            apr_snprintf(server_portstr, server_portstr_size, ":%d",\r
+                         server_port);\r
+        }\r
+    }\r
+\r
+    /* check if ProxyBlock directive on this host */\r
+    if (OK != ap_proxy_checkproxyblock(r, conf, conn->addr)) {\r
+        return ap_proxyerror(r, HTTP_FORBIDDEN,\r
+                             "Connect to remote machine blocked");\r
+    }\r
+    return OK;\r
+}\r
+\r
+static int is_socket_connected(apr_socket_t *sock)\r
+\r
+{\r
+    apr_size_t buffer_len = 1;\r
+    char test_buffer[1]; \r
+    apr_status_t socket_status;\r
+    apr_interval_time_t current_timeout;\r
+    \r
+    /* save timeout */\r
+    apr_socket_timeout_get(sock, &current_timeout);\r
+    /* set no timeout */\r
+    apr_socket_timeout_set(sock, 0);\r
+    socket_status = apr_socket_recv(sock, test_buffer, &buffer_len);\r
+    /* put back old timeout */\r
+    apr_socket_timeout_set(sock, current_timeout);\r
+    if (APR_STATUS_IS_EOF(socket_status))\r
+        return 0;\r
+    else\r
+        return 1;\r
+}\r
+\r
+PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,\r
+                                            proxy_conn_rec *conn,\r
+                                            proxy_worker *worker,\r
+                                            server_rec *s)\r
+{\r
+    apr_status_t rv;\r
+    int connected = 0;\r
+    int loglevel;\r
+    apr_sockaddr_t *backend_addr = conn->addr;\r
+    apr_socket_t *newsock;\r
+    \r
+    if (conn->sock) {\r
+        /* This increases the connection pool size\r
+         * but the number of dropped connections is\r
+         * relatively small compared to connection lifetime\r
+         */\r
+        if (!(connected = is_socket_connected(conn->sock))) {        \r
+            apr_socket_close(conn->sock);\r
+            conn->sock = NULL;\r
+        }\r
+    }\r
+    while (backend_addr && !connected) {\r
+        if ((rv = apr_socket_create(&newsock, backend_addr->family,\r
+                                SOCK_STREAM, APR_PROTO_TCP,\r
+                                conn->pool)) != APR_SUCCESS) {\r
+            loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;\r
+            ap_log_error(APLOG_MARK, loglevel, rv, s,\r
+                         "proxy: %s: error creating fam %d socket for target %s",\r
+                         proxy_function,\r
+                         backend_addr->family,\r
+                         worker->hostname);\r
+            /* this could be an IPv6 address from the DNS but the\r
+             * local machine won't give us an IPv6 socket; hopefully the\r
+             * DNS returned an additional address to try\r
+             */\r
+            backend_addr = backend_addr->next;\r
+            continue;\r
+        }\r
+\r
+#if !defined(TPF) && !defined(BEOS)\r
+        if (worker->recv_buffer_size > 0 &&\r
+            (rv = apr_socket_opt_set(newsock, APR_SO_RCVBUF,\r
+                                     worker->recv_buffer_size))) {\r
+            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,\r
+                         "apr_socket_opt_set(SO_RCVBUF): Failed to set "\r
+                         "ProxyReceiveBufferSize, using default");\r
+        }\r
+#endif\r
+\r
+        /* Set a timeout on the socket */\r
+        if (worker->timeout_set == 1) {\r
+            apr_socket_timeout_set(newsock, worker->timeout);\r
+        }\r
+        else {\r
+             apr_socket_timeout_set(newsock, s->timeout);\r
+        }\r
+        /* Set a keepalive option */\r
+        if (worker->keepalive) {\r
+            if ((rv = apr_socket_opt_set(newsock, \r
+                            APR_SO_KEEPALIVE, 1)) != APR_SUCCESS) {\r
+                ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,\r
+                             "apr_socket_opt_set(SO_KEEPALIVE): Failed to set"\r
+                             " Keepalive");\r
+            }\r
+        }\r
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,\r
+                     "proxy: %s: fam %d socket created to connect to %s",\r
+                     proxy_function, backend_addr->family, worker->hostname);\r
+\r
+        /* make the connection out of the socket */\r
+        rv = apr_socket_connect(newsock, backend_addr);\r
+\r
+        /* if an error occurred, loop round and try again */\r
+        if (rv != APR_SUCCESS) {\r
+            apr_socket_close(newsock);\r
+            loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;\r
+            ap_log_error(APLOG_MARK, loglevel, rv, s,\r
+                         "proxy: %s: attempt to connect to %pI (%s) failed",\r
+                         proxy_function,\r
+                         backend_addr,\r
+                         worker->hostname);\r
+            backend_addr = backend_addr->next;\r
+            continue;\r
+        }\r
+        \r
+        conn->sock   = newsock;\r
+        connected    = 1;\r
+    }\r
+    /* Put the entire worker to error state if\r
+     * the PROXY_WORKER_IGNORE_ERRORS flag is not set.\r
+     * Altrough some connections may be alive\r
+     * no further connections to the worker could be made\r
+     */\r
+    if (!connected && PROXY_WORKER_IS_USABLE(worker) &&\r
+        !(worker->s->status & PROXY_WORKER_IGNORE_ERRORS)) {\r
+        worker->s->status |= PROXY_WORKER_IN_ERROR;\r
+        worker->s->error_time = apr_time_now();\r
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,\r
+            "ap_proxy_connect_backend disabling worker for (%s)",\r
+            worker->hostname);\r
+    }\r
+    else {\r
+        worker->s->error_time = 0;\r
+        worker->s->retries = 0;\r
+    }\r
+    return connected ? OK : DECLINED;\r
+}\r
+\r
+PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function,\r
+                                              proxy_conn_rec *conn,\r
+                                              conn_rec *c,\r
+                                              server_rec *s)\r
+{\r
+    apr_sockaddr_t *backend_addr = conn->addr;\r
+\r
+    /* The socket is now open, create a new backend server connection \r
+    * \r
+    */\r
+    conn->connection = ap_run_create_connection(c->pool, s, conn->sock,\r
+                                                c->id, c->sbh,\r
+                                                c->bucket_alloc);\r
+\r
+    if (!conn->connection) {\r
+        /* the peer reset the connection already; ap_run_create_connection() \r
+        * closed the socket\r
+        */\r
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,\r
+                     s, "proxy: %s: an error occurred creating a "\r
+                     "new connection to %pI (%s)", proxy_function,\r
+                     backend_addr, conn->hostname);\r
+        /* XXX: Will be closed when proxy_conn is closed */\r
+        apr_socket_close(conn->sock);\r
+        conn->sock = NULL;\r
+        return HTTP_INTERNAL_SERVER_ERROR;\r
+    }\r
+    /* register the connection cleanup to client connection\r
+     * so that the connection can be closed or reused\r
+     */\r
+    apr_pool_cleanup_register(c->pool, (void *)conn,\r
+                              connection_cleanup,\r
+                              apr_pool_cleanup_null);      \r
+\r
+    /* For ssl connection to backend */\r
+    if (conn->is_ssl) {\r
+        if (!ap_proxy_ssl_enable(conn->connection)) {\r
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0,\r
+                         s, "proxy: %s: failed to enable ssl support "\r
+                         "for %pI (%s)", proxy_function, \r
+                         backend_addr, conn->hostname);\r
+            return HTTP_INTERNAL_SERVER_ERROR;\r
+        }\r
+    }\r
+    else {\r
+        /* TODO: See if this will break FTP */\r
+        ap_proxy_ssl_disable(conn->connection);\r
+    }\r
+\r
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,\r
+                 "proxy: %s: connection complete to %pI (%s)",\r
+                 proxy_function, backend_addr, conn->hostname);\r
+\r
+    /* set up the connection filters */\r
+    ap_run_pre_connection(conn->connection, conn->sock);\r
+\r
+    return OK;\r
+}\r
+\r
+int ap_proxy_lb_workers(void)\r
+{\r
+    /* Since we can't resize the scoreboard when reconfiguring, we\r
+     * have to impose a limit on the number of workers, we are\r
+     * able to reconfigure to.\r
+     */\r
+    if (!lb_workers_limit)\r
+       lb_workers_limit = proxy_lb_workers + PROXY_DYNAMIC_BALANCER_LIMIT;\r
+    return lb_workers_limit;\r
+}\r