]> granicus.if.org Git - apache/commitdiff
Reformat code to no tab and no CR-LF
authorMladen Turk <mturk@apache.org>
Tue, 28 Sep 2004 16:54:29 +0000 (16:54 +0000)
committerMladen Turk <mturk@apache.org>
Tue, 28 Sep 2004 16:54:29 +0000 (16:54 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@105320 13f79535-47bb-0310-9956-ffa450edef68

modules/proxy/mod_proxy.h
modules/proxy/proxy_ajp.c
modules/proxy/proxy_balancer.c
modules/proxy/proxy_connect.c
modules/proxy/proxy_ftp.c
modules/proxy/proxy_util.c

index 20b26dad4863c4ad415e5a265de34d4a38d11a83..227d72e04fe1872853545133d67237d903fca2e2 100644 (file)
-/* 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
+/* 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 workers that can be added when reconfiguring.
+ * If this limit is reached you must stop and restart the server.
+ */
+#define PROXY_DYNAMIC_BALANCER_LIMIT    16
+/**
+ * Calculate number of maximum number of workers in scoreboard.
+ * @return  number of workers to allocate in the scoreboard
+ */
+int ap_proxy_lb_workers(void);
+
+/* For proxy_util */
+extern module PROXY_DECLARE_DATA proxy_module;
+
+extern int PROXY_DECLARE_DATA proxy_lb_workers;
+
+#endif /*MOD_PROXY_H*/
index a0d7f2790009c0e0842dcdfa8bee3d503cdc491c..13c9b102cf28abf6f7971720145ca5d3644e0241 100644 (file)
@@ -303,7 +303,7 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
                          "ajp_read_header failed");
             break;
         }
-       result = ajp_parse_type(r, conn->data);
+        result = ajp_parse_type(r, conn->data);
     }
     apr_brigade_destroy(input_brigade);
 
index 1f38a0487c0668b7c5463c3c144834c1cd75b5f1..4dadd59e1b5aab36b56b7d141634d06001bdd22b 100644 (file)
@@ -45,7 +45,7 @@ static int init_runtime_score(proxy_server_conf *conf, server_rec *s, proxy_bala
 
     for (i = 0; i < balancer->workers->nelts; i++) {
         ap_proxy_initialize_worker_share(conf, workers);
-       ap_proxy_initialize_worker(workers, s);
+    ap_proxy_initialize_worker(workers, s);
         workers->s->status = PROXY_WORKER_INITIALIZED; 
         ++workers;
     }
@@ -284,19 +284,19 @@ static proxy_worker *find_best_worker(proxy_balancer *balancer,
          * not in error state or not disabled.
          */
         if (PROXY_WORKER_IS_USABLE(worker)) {
-           worker->s->lbstatus += worker->s->lbfactor;
-               total_factor += worker->s->lbfactor;
-           if (!candidate || worker->s->lbstatus > candidate->s->lbstatus)
-                       candidate = worker;
-           }
+            worker->s->lbstatus += worker->s->lbfactor;
+            total_factor += worker->s->lbfactor;
+            if (!candidate || worker->s->lbstatus > candidate->s->lbstatus)
+                candidate = worker;
+        }
         worker++;
     }
 
     if (candidate) {
-           candidate->s->lbstatus -= total_factor;
-           candidate->s->elected++;
+        candidate->s->lbstatus -= total_factor;
+        candidate->s->elected++;
         PROXY_BALANCER_UNLOCK(balancer);
-           return candidate;
+        return candidate;
     }
     else {
         PROXY_BALANCER_UNLOCK(balancer);
@@ -399,13 +399,13 @@ static int proxy_balancer_pre_request(proxy_worker **worker,
              * not in error state or not disabled.
              */
             if (PROXY_WORKER_IS_USABLE(workers)) {
-               workers->s->lbstatus += workers->s->lbfactor;
-                   total_factor += workers->s->lbfactor;
-           }
+                workers->s->lbstatus += workers->s->lbfactor;
+                total_factor += workers->s->lbfactor;
+            }
             workers++;
         }
-           runtime->s->lbstatus -= total_factor;
-           runtime->s->elected++;
+        runtime->s->lbstatus -= total_factor;
+        runtime->s->elected++;
 
         *worker = runtime;
     }
@@ -787,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, s, balancer);
+        init_runtime_score(conf, s, balancer);
             balancer++;
         }
         s = s->next;
index 7dd16e34d3ff3664818f3980fb534e9507f4bc19..fb672db1926e7b7da7dc55d77741d4fe8749b682 100644 (file)
@@ -58,8 +58,8 @@ allowed_port(proxy_server_conf *conf, int port)
     int *list = (int *) conf->allowed_connect_ports->elts;
 
     for(i = 0; i < conf->allowed_connect_ports->nelts; i++) {
-       if(port == list[i])
-           return 1;
+    if(port == list[i])
+        return 1;
     }
     return 0;
 }
@@ -69,10 +69,10 @@ int ap_proxy_connect_canon(request_rec *r, char *url)
 {
 
     if (r->method_number != M_CONNECT) {
-       return DECLINED;
+    return DECLINED;
     }
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                "proxy: CONNECT: canonicalising URL %s", url);
+         "proxy: CONNECT: canonicalising URL %s", url);
 
     return OK;
 }
@@ -104,11 +104,11 @@ int ap_proxy_connect_handler(request_rec *r, proxy_worker *worker,
     /* is this for us? */
     if (r->method_number != M_CONNECT) {
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                    "proxy: CONNECT: declining URL %s", url);
-       return DECLINED;
+             "proxy: CONNECT: declining URL %s", url);
+    return DECLINED;
     }
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                "proxy: CONNECT: serving URL %s", url);
+         "proxy: CONNECT: serving URL %s", url);
 
 
     /*
@@ -119,50 +119,50 @@ int ap_proxy_connect_handler(request_rec *r, proxy_worker *worker,
 
     /* we break the URL into host, port, uri */
     if (APR_SUCCESS != apr_uri_parse_hostinfo(p, url, &uri)) {
-       return ap_proxyerror(r, HTTP_BAD_REQUEST,
-                            apr_pstrcat(p, "URI cannot be parsed: ", url, NULL));
+    return ap_proxyerror(r, HTTP_BAD_REQUEST,
+                 apr_pstrcat(p, "URI cannot be parsed: ", url, NULL));
     }
 
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                "proxy: CONNECT: connecting %s to %s:%d", url, uri.hostname, uri.port);
+         "proxy: CONNECT: connecting %s to %s:%d", url, uri.hostname, uri.port);
 
     /* do a DNS lookup for the destination host */
     err = apr_sockaddr_info_get(&uri_addr, uri.hostname, APR_UNSPEC, uri.port, 0, p);
 
     /* are we connecting directly, or via a proxy? */
     if (proxyname) {
-       connectname = proxyname;
-       connectport = proxyport;
+    connectname = proxyname;
+    connectport = proxyport;
         err = apr_sockaddr_info_get(&connect_addr, proxyname, APR_UNSPEC, proxyport, 0, p);
     }
     else {
-       connectname = uri.hostname;
-       connectport = uri.port;
-       connect_addr = uri_addr;
+    connectname = uri.hostname;
+    connectport = uri.port;
+    connect_addr = uri_addr;
     }
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                "proxy: CONNECT: connecting to remote proxy %s on port %d", connectname, connectport);
+         "proxy: CONNECT: connecting to remote proxy %s on port %d", connectname, connectport);
 
     /* check if ProxyBlock directive on this host */
     if (OK != ap_proxy_checkproxyblock(r, conf, uri_addr)) {
-       return ap_proxyerror(r, HTTP_FORBIDDEN,
-                            "Connect to remote machine blocked");
+    return ap_proxyerror(r, HTTP_FORBIDDEN,
+                 "Connect to remote machine blocked");
     }
 
     /* Check if it is an allowed port */
     if (conf->allowed_connect_ports->nelts == 0) {
-       /* Default setting if not overridden by AllowCONNECT */
-       switch (uri.port) {
-           case APR_URI_HTTPS_DEFAULT_PORT:
-           case APR_URI_SNEWS_DEFAULT_PORT:
-               break;
-           default:
+    /* Default setting if not overridden by AllowCONNECT */
+    switch (uri.port) {
+        case APR_URI_HTTPS_DEFAULT_PORT:
+        case APR_URI_SNEWS_DEFAULT_PORT:
+        break;
+        default:
                 /* XXX can we call ap_proxyerror() here to get a nice log message? */
-               return HTTP_FORBIDDEN;
-       }
+        return HTTP_FORBIDDEN;
+    }
     } else if(!allowed_port(conf, uri.port)) {
         /* XXX can we call ap_proxyerror() here to get a nice log message? */
-       return HTTP_FORBIDDEN;
+    return HTTP_FORBIDDEN;
     }
 
     /*
@@ -175,7 +175,7 @@ int ap_proxy_connect_handler(request_rec *r, proxy_worker *worker,
      * until we get a successful connection
      */
     if (APR_SUCCESS != err) {
-       return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p,
+    return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p,
                              "DNS lookup failure for: ",
                              connectname, NULL));
     }
@@ -222,26 +222,26 @@ int ap_proxy_connect_handler(request_rec *r, proxy_worker *worker,
      * the CONNECT request on to it.
      */
     if (proxyport) {
-       /* FIXME: Error checking ignored.
-        */
+    /* FIXME: Error checking ignored.
+     */
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                    "proxy: CONNECT: sending the CONNECT request to the remote proxy");
+             "proxy: CONNECT: sending the CONNECT request to the remote proxy");
         nbytes = apr_snprintf(buffer, sizeof(buffer),
-                             "CONNECT %s HTTP/1.0" CRLF, r->uri);
+                  "CONNECT %s HTTP/1.0" CRLF, r->uri);
         apr_socket_send(sock, buffer, &nbytes);
         nbytes = apr_snprintf(buffer, sizeof(buffer),
-                             "Proxy-agent: %s" CRLF CRLF, ap_get_server_version());
+                  "Proxy-agent: %s" CRLF CRLF, ap_get_server_version());
         apr_socket_send(sock, buffer, &nbytes);
     }
     else {
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                    "proxy: CONNECT: Returning 200 OK Status");
+             "proxy: CONNECT: Returning 200 OK Status");
         nbytes = apr_snprintf(buffer, sizeof(buffer),
-                             "HTTP/1.0 200 Connection Established" CRLF);
+                  "HTTP/1.0 200 Connection Established" CRLF);
         ap_xlate_proto_to_ascii(buffer, nbytes);
         apr_socket_send(client_socket, buffer, &nbytes);
         nbytes = apr_snprintf(buffer, sizeof(buffer),
-                             "Proxy-agent: %s" CRLF CRLF, ap_get_server_version());
+                  "Proxy-agent: %s" CRLF CRLF, ap_get_server_version());
         ap_xlate_proto_to_ascii(buffer, nbytes);
         apr_socket_send(client_socket, buffer, &nbytes);
 #if 0
@@ -256,7 +256,7 @@ int ap_proxy_connect_handler(request_rec *r, proxy_worker *worker,
     }
 
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                "proxy: CONNECT: setting up poll()");
+         "proxy: CONNECT: setting up poll()");
 
     /*
      * Step Four: Handle Data Transfer
@@ -268,7 +268,7 @@ int ap_proxy_connect_handler(request_rec *r, proxy_worker *worker,
 
     if ((rv = apr_pollset_create(&pollset, 2, r->pool, 0)) != APR_SUCCESS)
     {
-       apr_socket_close(sock);
+    apr_socket_close(sock);
         ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
             "proxy: CONNECT: error apr_pollset_create()");
         return HTTP_INTERNAL_SERVER_ERROR;
@@ -288,7 +288,7 @@ int ap_proxy_connect_handler(request_rec *r, proxy_worker *worker,
 
     while (1) { /* Infinite loop until error (one side closes the connection) */
         if ((rv = apr_pollset_poll(pollset, -1, &pollcnt, &signalled)) != APR_SUCCESS) {
-           apr_socket_close(sock);
+        apr_socket_close(sock);
             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "proxy: CONNECT: error apr_poll()");
             return HTTP_INTERNAL_SERVER_ERROR;
         }
@@ -375,7 +375,7 @@ int ap_proxy_connect_handler(request_rec *r, proxy_worker *worker,
     }
 
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                "proxy: CONNECT: finished with poll() - cleaning up");
+         "proxy: CONNECT: finished with poll() - cleaning up");
 
     /*
      * Step Five: Clean Up
@@ -396,10 +396,10 @@ static void ap_proxy_connect_register_hook(apr_pool_t *p)
 
 module AP_MODULE_DECLARE_DATA proxy_connect_module = {
     STANDARD20_MODULE_STUFF,
-    NULL,              /* create per-directory config structure */
-    NULL,              /* merge per-directory config structures */
-    NULL,              /* create per-server config structure */
-    NULL,              /* merge per-server config structures */
-    NULL,              /* command apr_table_t */
-    ap_proxy_connect_register_hook     /* register hooks */
+    NULL,       /* create per-directory config structure */
+    NULL,       /* merge per-directory config structures */
+    NULL,       /* create per-server config structure */
+    NULL,       /* merge per-server config structures */
+    NULL,       /* command apr_table_t */
+    ap_proxy_connect_register_hook  /* register hooks */
 };
index e82636d26596e5c846af92bc061d07bfb7d2f222..2efcda67bde020007581350d835b917fa2d849dd 100644 (file)
@@ -96,7 +96,7 @@ static int ftp_check_globbingchars(const char *path)
 {
     for ( ; *path; ++path) {
         if (*path == '\\')
-           ++path;
+        ++path;
         if (path != '\0' && strchr(FTP_GLOBBING_CHARS, *path) != NULL)
             return TRUE;
     }
@@ -1531,39 +1531,39 @@ int ap_proxy_ftp_handler(request_rec *r, proxy_worker *worker, proxy_server_conf
                                r, origin, bb, &ftpmessage);
         /* then extract the Last-Modified time from it (YYYYMMDDhhmmss or YYYYMMDDhhmmss.xxx GMT). */
         if (rc == 213) {
-           struct {
-               char YYYY[4+1];
-               char MM[2+1];
-               char DD[2+1];
-               char hh[2+1];
-               char mm[2+1];
-               char ss[2+1];
-           } time_val;
-           if (6 == sscanf(ftpmessage, "%4[0-9]%2[0-9]%2[0-9]%2[0-9]%2[0-9]%2[0-9]",
-               time_val.YYYY, time_val.MM, time_val.DD, time_val.hh, time_val.mm, time_val.ss)) {
+        struct {
+            char YYYY[4+1];
+        char MM[2+1];
+        char DD[2+1];
+        char hh[2+1];
+        char mm[2+1];
+        char ss[2+1];
+        } time_val;
+        if (6 == sscanf(ftpmessage, "%4[0-9]%2[0-9]%2[0-9]%2[0-9]%2[0-9]%2[0-9]",
+            time_val.YYYY, time_val.MM, time_val.DD, time_val.hh, time_val.mm, time_val.ss)) {
                 struct tm tms;
-               memset (&tms, '\0', sizeof tms);
-               tms.tm_year = atoi(time_val.YYYY) - 1900;
-               tms.tm_mon  = atoi(time_val.MM)   - 1;
-               tms.tm_mday = atoi(time_val.DD);
-               tms.tm_hour = atoi(time_val.hh);
-               tms.tm_min  = atoi(time_val.mm);
-               tms.tm_sec  = atoi(time_val.ss);
+        memset (&tms, '\0', sizeof tms);
+        tms.tm_year = atoi(time_val.YYYY) - 1900;
+        tms.tm_mon  = atoi(time_val.MM)   - 1;
+        tms.tm_mday = atoi(time_val.DD);
+        tms.tm_hour = atoi(time_val.hh);
+        tms.tm_min  = atoi(time_val.mm);
+        tms.tm_sec  = atoi(time_val.ss);
 #ifdef HAVE_TIMEGM /* Does system have timegm()? */
-               mtime = timegm(&tms);
-               mtime *= APR_USEC_PER_SEC;
+        mtime = timegm(&tms);
+        mtime *= APR_USEC_PER_SEC;
 #elif HAVE_GMTOFF /* does struct tm have a member tm_gmtoff? */
                 /* mktime will subtract the local timezone, which is not what we want.
-                * Add it again because the MDTM string is GMT
-                */
-               mtime = mktime(&tms);
-               mtime += tms.tm_gmtoff;
-               mtime *= APR_USEC_PER_SEC;
+         * Add it again because the MDTM string is GMT
+         */
+        mtime = mktime(&tms);
+        mtime += tms.tm_gmtoff;
+        mtime *= APR_USEC_PER_SEC;
 #else
-               mtime = 0L;
+        mtime = 0L;
 #endif
             }
-       }
+    }
 #endif /* USE_MDTM */
 /* FIXME: Handle range requests - send REST */
         buf = apr_pstrcat(p, "RETR ", ftp_escape_globbingchars(p, path), CRLF, NULL);
index 2819ca800178825d5656aa284bbd0f414e180961..4293e1e1d2bd48b472df5ed292089597165d1a61 100644 (file)
-/* 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
+/* 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 */
+int PROXY_DECLARE_DATA proxy_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   = proxy_lb_workers;
+    /* Increase the total worker count */
+    proxy_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 = proxy_lb_workers;
+    /* Increase the total worker count */
+    proxy_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;
+
+    runtime = apr_array_push(balancer->workers);
+    memcpy(runtime, worker, sizeof(proxy_worker));
+    runtime->id = proxy_lb_workers;
+    /* Increase the total runtime count */
+    proxy_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);
+    if (!score)
+        ap_log_perror(APLOG_MARK, APLOG_ERR, 0, conf->pool,
+              "proxy: ap_get_scoreboard_lb(%d) failed for worker %s",
+              worker->id, worker->name);
+    }
+#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);
+    else
+    *worker->s->route = '\0';
+    if (worker->redirect)
+        strcpy(worker->s->redirect, worker->redirect);
+    else
+    *worker->s->redirect = '\0';
+}
+
+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 %d for (%s) min=%d max=%d smax=%d",
+             worker->id, 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 %d for (%s)",
+             worker->id, 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)
+{
+    /* Since we can't resize the scoreboard when reconfiguring, we
+     * have to impose a limit on the number of workers, we are
+     * able to reconfigure to.
+     */
+    if (!lb_workers_limit)
+    lb_workers_limit = proxy_lb_workers + PROXY_DYNAMIC_BALANCER_LIMIT;
+    return lb_workers_limit;
+}