Skip to content
Permalink
85f394d587
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
1110 lines (1002 sloc) 45.9 KB
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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
/**
* @file mod_proxy.h
* @brief Proxy Extension Module for Apache
*
* @defgroup MOD_PROXY mod_proxy
* @ingroup APACHE_MODS
* @{
*/
#include "apr_hooks.h"
#include "apr_optional.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 "apr_uuid.h"
#include "util_mutex.h"
#include "apr_global_mutex.h"
#include "apr_thread_mutex.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"
#include "ap_provider.h"
#include "ap_slotmem.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
};
#define BALANCER_PREFIX "balancer://"
#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 */
/* Set this to -1, which complies with RFC2616 by not setting
* max-forwards if the client didn't send it to us.
*/
#define DEFAULT_MAX_FORWARDS -1
typedef struct proxy_balancer proxy_balancer;
typedef struct proxy_worker proxy_worker;
typedef struct proxy_conn_pool proxy_conn_pool;
typedef struct proxy_balancer_method proxy_balancer_method;
/* 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 */
ap_regex_t *regexp; /* compiled regex (if any) for the remote */
int use_regex; /* simple boolean. True if we have a regex pattern */
apr_port_t port; /* the port for this proxy */
};
#define PROXYPASS_NOCANON 0x01
#define PROXYPASS_INTERPOLATE 0x02
#define PROXYPASS_NOQUERY 0x04
struct proxy_alias {
const char *real;
const char *fake;
ap_regex_t *regex;
unsigned int flags;
proxy_balancer *balancer; /* only valid for reverse-proxys */
};
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 {
apr_array_header_t *proxies;
apr_array_header_t *sec_proxy;
apr_array_header_t *aliases;
apr_array_header_t *noproxies;
apr_array_header_t *dirconn;
apr_array_header_t *workers; /* non-balancer workers, eg ProxyPass http://example.com */
apr_array_header_t *balancers; /* list of balancers @ config time */
proxy_worker *forward; /* forward proxy worker */
proxy_worker *reverse; /* reverse "module-driven" proxy worker */
const char *domain; /* domain name to use in absence of a domain name in the request */
const char *id;
apr_pool_t *pool; /* Pool used for allocating this struct */
int req; /* true if proxy requests are enabled */
int max_balancers; /* maximum number of allowed balancers */
int bgrowth; /* number of post-config balancers can added */
enum {
via_off,
via_on,
via_block,
via_full
} viaopt; /* how to deal with proxy Via: headers */
apr_size_t recv_buffer_size;
apr_size_t io_buffer_size;
long maxfwd;
apr_interval_time_t timeout;
enum {
bad_error,
bad_ignore,
bad_body
} badopt; /* how to deal with bad headers */
enum {
status_off,
status_on,
status_full
} proxy_status; /* Status display options */
apr_sockaddr_t *source_address;
apr_global_mutex_t *mutex; /* global lock, for pool, etc */
ap_slotmem_instance_t *bslot; /* balancers shm data - runtime */
ap_slotmem_provider_t *storage;
unsigned int req_set:1;
unsigned int viaopt_set:1;
unsigned int recv_buffer_size_set:1;
unsigned int io_buffer_size_set:1;
unsigned int maxfwd_set:1;
unsigned int timeout_set:1;
unsigned int badopt_set:1;
unsigned int proxy_status_set:1;
unsigned int source_address_set:1;
unsigned int bgrowth_set:1;
unsigned int bal_persist:1;
unsigned int inherit:1;
unsigned int inherit_set:1;
unsigned int ppinherit:1;
unsigned int ppinherit_set:1;
} proxy_server_conf;
typedef struct {
const char *p; /* The path */
ap_regex_t *r; /* Is this a regex? */
/* FIXME
* ProxyPassReverse and friends are documented as working inside
* <Location>. But in fact they never have done in the case of
* more than one <Location>, because the server_conf can't see it.
* We need to move them to the per-dir config.
* Discussed in February 2005:
* http://marc.theaimsgroup.com/?l=apache-httpd-dev&m=110726027118798&w=2
*/
apr_array_header_t *raliases;
apr_array_header_t* cookie_paths;
apr_array_header_t* cookie_domains;
signed char p_is_fnmatch; /* Is the path an fnmatch candidate? */
signed char interpolate_env;
struct proxy_alias *alias;
/**
* 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
*/
unsigned int error_override:1;
unsigned int preserve_host:1;
unsigned int preserve_host_set:1;
unsigned int error_override_set:1;
unsigned int alias_set:1;
unsigned int add_forwarded_headers:1;
/** Named back references */
apr_array_header_t *refs;
} proxy_dir_conf;
/* if we interpolate env vars per-request, we'll need a per-request
* copy of the reverse proxy config
*/
typedef struct {
apr_array_header_t *raliases;
apr_array_header_t* cookie_paths;
apr_array_header_t* cookie_domains;
} proxy_req_conf;
typedef struct {
conn_rec *connection;
request_rec *r; /* Request record of the backend request
* that is used over the backend connection. */
proxy_worker *worker; /* Connection pool this connection belongs to */
apr_pool_t *pool; /* Subpool for hostname and addr data */
const char *hostname;
apr_sockaddr_t *addr; /* Preparsed remote address info */
apr_pool_t *scpool; /* Subpool used for socket and connection data */
apr_socket_t *sock; /* Connection socket */
void *data; /* per scheme connection data */
void *forward; /* opaque forward proxy data */
apr_uint32_t flags; /* Connection flags */
apr_port_t port;
unsigned int is_ssl:1;
unsigned int close:1; /* Close 'this' connection */
unsigned int need_flush:1; /* Flag to decide whether we need to flush the
* filter chain or not */
unsigned int inreslist:1; /* connection in apr_reslist? */
const char *uds_path; /* Unix domain socket path */
const char *ssl_hostname;/* Hostname (SNI) in use by SSL connection */
} 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 */
apr_reslist_t *res; /* Connection resource list */
proxy_conn_rec *conn; /* Single connection for prefork mpm */
};
/* Keep below in sync with proxy_util.c! */
/* worker status bits */
#define PROXY_WORKER_INITIALIZED 0x0001
#define PROXY_WORKER_IGNORE_ERRORS 0x0002
#define PROXY_WORKER_DRAIN 0x0004
#define PROXY_WORKER_GENERIC 0x0008
#define PROXY_WORKER_IN_SHUTDOWN 0x0010
#define PROXY_WORKER_DISABLED 0x0020
#define PROXY_WORKER_STOPPED 0x0040
#define PROXY_WORKER_IN_ERROR 0x0080
#define PROXY_WORKER_HOT_STANDBY 0x0100
#define PROXY_WORKER_FREE 0x0200
/* worker status flags */
#define PROXY_WORKER_INITIALIZED_FLAG 'O'
#define PROXY_WORKER_IGNORE_ERRORS_FLAG 'I'
#define PROXY_WORKER_DRAIN_FLAG 'N'
#define PROXY_WORKER_GENERIC_FLAG 'G'
#define PROXY_WORKER_IN_SHUTDOWN_FLAG 'U'
#define PROXY_WORKER_DISABLED_FLAG 'D'
#define PROXY_WORKER_STOPPED_FLAG 'S'
#define PROXY_WORKER_IN_ERROR_FLAG 'E'
#define PROXY_WORKER_HOT_STANDBY_FLAG 'H'
#define PROXY_WORKER_FREE_FLAG 'F'
#define PROXY_WORKER_NOT_USABLE_BITMAP ( PROXY_WORKER_IN_SHUTDOWN | \
PROXY_WORKER_DISABLED | PROXY_WORKER_STOPPED | PROXY_WORKER_IN_ERROR )
/* NOTE: these check the shared status */
#define PROXY_WORKER_IS_INITIALIZED(f) ( (f)->s->status & PROXY_WORKER_INITIALIZED )
#define PROXY_WORKER_IS_STANDBY(f) ( (f)->s->status & PROXY_WORKER_HOT_STANDBY )
#define PROXY_WORKER_IS_USABLE(f) ( ( !( (f)->s->status & PROXY_WORKER_NOT_USABLE_BITMAP) ) && \
PROXY_WORKER_IS_INITIALIZED(f) )
#define PROXY_WORKER_IS_DRAINING(f) ( (f)->s->status & PROXY_WORKER_DRAIN )
#define PROXY_WORKER_IS_GENERIC(f) ( (f)->s->status & PROXY_WORKER_GENERIC )
/* default worker retry timeout in seconds */
#define PROXY_WORKER_DEFAULT_RETRY 60
/* Some max char string sizes, for shm fields */
#define PROXY_WORKER_MAX_SCHEME_SIZE 16
#define PROXY_WORKER_MAX_ROUTE_SIZE 64
#define PROXY_BALANCER_MAX_ROUTE_SIZE PROXY_WORKER_MAX_ROUTE_SIZE
#define PROXY_WORKER_MAX_NAME_SIZE 96
#define PROXY_BALANCER_MAX_NAME_SIZE PROXY_WORKER_MAX_NAME_SIZE
#define PROXY_WORKER_MAX_HOSTNAME_SIZE 64
#define PROXY_BALANCER_MAX_HOSTNAME_SIZE PROXY_WORKER_MAX_HOSTNAME_SIZE
#define PROXY_BALANCER_MAX_STICKY_SIZE 64
/* RFC-1035 mentions limits of 255 for host-names and 253 for domain-names,
* dotted together(?) this would fit the below size (+ trailing NUL).
*/
#define PROXY_WORKER_RFC1035_NAME_SIZE 512
#define PROXY_MAX_PROVIDER_NAME_SIZE 16
#define PROXY_STRNCPY(dst, src) ap_proxy_strncpy((dst), (src), (sizeof(dst)))
#define PROXY_COPY_CONF_PARAMS(w, c) \
do { \
(w)->s->timeout = (c)->timeout; \
(w)->s->timeout_set = (c)->timeout_set; \
(w)->s->recv_buffer_size = (c)->recv_buffer_size; \
(w)->s->recv_buffer_size_set = (c)->recv_buffer_size_set; \
(w)->s->io_buffer_size = (c)->io_buffer_size; \
(w)->s->io_buffer_size_set = (c)->io_buffer_size_set; \
} while (0)
/* use 2 hashes */
typedef struct {
unsigned int def;
unsigned int fnv;
} proxy_hashes ;
/* Runtime worker status informations. Shared in scoreboard */
/* The addition of member uds_path in 2.4.7 was an incompatible API change. */
typedef struct {
char name[PROXY_WORKER_MAX_NAME_SIZE];
char scheme[PROXY_WORKER_MAX_SCHEME_SIZE]; /* scheme to use ajp|http|https */
char hostname[PROXY_WORKER_MAX_HOSTNAME_SIZE]; /* remote backend address */
char route[PROXY_WORKER_MAX_ROUTE_SIZE]; /* balancing route */
char redirect[PROXY_WORKER_MAX_ROUTE_SIZE]; /* temporary balancing redirection route */
char flusher[PROXY_WORKER_MAX_SCHEME_SIZE]; /* flush provider used by mod_proxy_fdpass */
char uds_path[PROXY_WORKER_MAX_NAME_SIZE]; /* path to worker's unix domain socket if applicable */
int lbset; /* load balancer cluster set */
int retries; /* number of retries on this worker */
int lbstatus; /* Current lbstatus */
int lbfactor; /* dynamic lbfactor */
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 */
int flush_wait; /* poll wait time in microseconds if flush_auto */
int index; /* shm array index */
proxy_hashes hash; /* hash of worker name */
unsigned int status; /* worker status bitfield */
enum {
flush_off,
flush_on,
flush_auto
} flush_packets; /* control AJP flushing */
apr_time_t updated; /* timestamp of last update */
apr_time_t error_time; /* time of the last error */
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 retry; /* retry interval */
apr_interval_time_t timeout; /* connection timeout */
apr_interval_time_t acquire; /* acquire timeout when the maximum number of connections is exceeded */
apr_interval_time_t ping_timeout;
apr_interval_time_t conn_timeout;
apr_size_t recv_buffer_size;
apr_size_t io_buffer_size;
apr_size_t elected; /* Number of times the worker was elected */
apr_size_t busy; /* busyness factor */
apr_port_t port;
apr_off_t transferred;/* Number of bytes transferred to remote */
apr_off_t read; /* Number of bytes read from remote */
void *context; /* general purpose storage */
unsigned int keepalive:1;
unsigned int disablereuse:1;
unsigned int is_address_reusable:1;
unsigned int retry_set:1;
unsigned int timeout_set:1;
unsigned int acquire_set:1;
unsigned int ping_timeout_set:1;
unsigned int conn_timeout_set:1;
unsigned int recv_buffer_size_set:1;
unsigned int io_buffer_size_set:1;
unsigned int keepalive_set:1;
unsigned int disablereuse_set:1;
unsigned int was_malloced:1;
} proxy_worker_shared;
#define ALIGNED_PROXY_WORKER_SHARED_SIZE (APR_ALIGN_DEFAULT(sizeof(proxy_worker_shared)))
/* Worker configuration */
struct proxy_worker {
proxy_hashes hash; /* hash of worker name */
unsigned int local_status; /* status of per-process worker */
proxy_conn_pool *cp; /* Connection pool to use */
proxy_worker_shared *s; /* Shared data */
proxy_balancer *balancer; /* which balancer am I in? */
apr_thread_mutex_t *tmutex; /* Thread lock for updating address cache */
void *context; /* general purpose storage */
};
/*
* Time to wait (in microseconds) to find out if more data is currently
* available at the backend.
*/
#define PROXY_FLUSH_WAIT 10000
typedef struct {
char sticky_path[PROXY_BALANCER_MAX_STICKY_SIZE]; /* URL sticky session identifier */
char sticky[PROXY_BALANCER_MAX_STICKY_SIZE]; /* sticky session identifier */
char lbpname[PROXY_MAX_PROVIDER_NAME_SIZE]; /* lbmethod provider name */
char nonce[APR_UUID_FORMATTED_LENGTH + 1];
char name[PROXY_BALANCER_MAX_NAME_SIZE];
char sname[PROXY_BALANCER_MAX_NAME_SIZE];
char vpath[PROXY_BALANCER_MAX_ROUTE_SIZE];
char vhost[PROXY_BALANCER_MAX_HOSTNAME_SIZE];
apr_interval_time_t timeout; /* Timeout for waiting on free connection */
apr_time_t wupdated; /* timestamp of last change to workers list */
int max_attempts; /* Number of attempts before failing */
int index; /* shm array index */
proxy_hashes hash;
unsigned int sticky_force:1; /* Disable failover for sticky sessions */
unsigned int scolonsep:1; /* true if ';' seps sticky session paths */
unsigned int max_attempts_set:1;
unsigned int was_malloced:1;
unsigned int need_reset:1;
unsigned int vhosted:1;
unsigned int inactive:1;
unsigned int forcerecovery:1;
char sticky_separator; /* separator for sessionid/route */
} proxy_balancer_shared;
#define ALIGNED_PROXY_BALANCER_SHARED_SIZE (APR_ALIGN_DEFAULT(sizeof(proxy_balancer_shared)))
struct proxy_balancer {
apr_array_header_t *workers; /* initially configured workers */
apr_array_header_t *errstatuses; /* statuses to force members into error */
ap_slotmem_instance_t *wslot; /* worker shm data - runtime */
ap_slotmem_provider_t *storage;
int growth; /* number of post-config workers can added */
int max_workers; /* maximum number of allowed workers */
proxy_hashes hash;
apr_time_t wupdated; /* timestamp of last change to workers list */
proxy_balancer_method *lbmethod;
apr_global_mutex_t *gmutex; /* global lock for updating list of workers */
apr_thread_mutex_t *tmutex; /* Thread lock for updating shm */
proxy_server_conf *sconf;
void *context; /* general purpose storage */
proxy_balancer_shared *s; /* Shared data */
int failontimeout; /* Whether to mark a member in Err if IO timeout occurs */
};
struct proxy_balancer_method {
const char *name; /* name of the load balancer method*/
proxy_worker *(*finder)(proxy_balancer *balancer,
request_rec *r);
void *context; /* general purpose storage */
apr_status_t (*reset)(proxy_balancer *balancer, server_rec *s);
apr_status_t (*age)(proxy_balancer *balancer, server_rec *s);
apr_status_t (*updatelbstatus)(proxy_balancer *balancer, proxy_worker *elected, server_rec *s);
};
#define PROXY_THREAD_LOCK(x) ( (x) && (x)->tmutex ? apr_thread_mutex_lock((x)->tmutex) : APR_SUCCESS)
#define PROXY_THREAD_UNLOCK(x) ( (x) && (x)->tmutex ? apr_thread_mutex_unlock((x)->tmutex) : APR_SUCCESS)
#define PROXY_GLOBAL_LOCK(x) ( (x) && (x)->gmutex ? apr_global_mutex_lock((x)->gmutex) : APR_SUCCESS)
#define PROXY_GLOBAL_UNLOCK(x) ( (x) && (x)->gmutex ? apr_global_mutex_unlock((x)->gmutex) : APR_SUCCESS)
/* 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
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))
/**
* request status hook
* It is called after all proxy processing has been done. This gives other
* modules a chance to create default content on failure, for example
*/
APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, request_status,
(int *status, request_rec *r))
/* proxy_util.c */
PROXY_DECLARE(apr_status_t) ap_proxy_strncpy(char *dst, const char *src,
apr_size_t dlen);
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 forcedec, int proxyreq);
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(int) ap_proxyerror(request_rec *r, int statuscode, const char *message);
PROXY_DECLARE(int) ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf, apr_sockaddr_t *uri_addr);
/** Test whether the hostname/address of the request are blocked by the ProxyBlock
* configuration.
* @param r request
* @param conf server configuration
* @param hostname hostname from request URI
* @param addr resolved address of hostname, or NULL if not known
* @return OK on success, or else an errro
*/
PROXY_DECLARE(int) ap_proxy_checkproxyblock2(request_rec *r, proxy_server_conf *conf,
const char *hostname, apr_sockaddr_t *addr);
PROXY_DECLARE(int) ap_proxy_pre_http_request(conn_rec *c, request_rec *r);
/* 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 *, request_rec *);
PROXY_DECLARE(apr_status_t) ap_proxy_ssl_connection_cleanup(proxy_conn_rec *conn,
request_rec *r);
PROXY_DECLARE(int) ap_proxy_ssl_enable(conn_rec *c);
PROXY_DECLARE(int) ap_proxy_ssl_disable(conn_rec *c);
PROXY_DECLARE(int) ap_proxy_conn_is_https(conn_rec *c);
PROXY_DECLARE(const char *) ap_proxy_ssl_val(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, const char *var);
/* Header mapping functions, and a typedef of their signature */
PROXY_DECLARE(const char *) ap_proxy_location_reverse_map(request_rec *r, proxy_dir_conf *conf, const char *url);
PROXY_DECLARE(const char *) ap_proxy_cookie_reverse_map(request_rec *r, proxy_dir_conf *conf, const char *str);
#if !defined(WIN32)
typedef const char *(*ap_proxy_header_reverse_map_fn)(request_rec *,
proxy_dir_conf *, const char *);
#elif defined(PROXY_DECLARE_STATIC)
typedef const char *(__stdcall *ap_proxy_header_reverse_map_fn)(request_rec *,
proxy_dir_conf *, const char *);
#elif defined(PROXY_DECLARE_EXPORT)
typedef __declspec(dllexport) const char *
(__stdcall *ap_proxy_header_reverse_map_fn)(request_rec *,
proxy_dir_conf *, const char *);
#else
typedef __declspec(dllimport) const char *
(__stdcall *ap_proxy_header_reverse_map_fn)(request_rec *,
proxy_dir_conf *, const char *);
#endif
/* Connection pool API */
/**
* Return the user-land, UDS aware worker name
* @param p memory pool used for displaying worker name
* @param worker the worker
* @return name
*/
PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p,
proxy_worker *worker);
/**
* Get the worker from proxy configuration
* @param p memory pool used for finding worker
* @param balancer the balancer that the worker belongs to
* @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_balancer *balancer,
proxy_server_conf *conf,
const char *url);
/**
* Define and Allocate space for the worker to proxy configuration
* @param p memory pool to allocate worker from
* @param worker the new worker
* @param balancer the balancer that the worker belongs to
* @param conf current proxy server configuration
* @param url url containing worker name
* @param do_malloc true if shared struct should be malloced
* @return error message or NULL if successful (*worker is new worker)
*/
PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p,
proxy_worker **worker,
proxy_balancer *balancer,
proxy_server_conf *conf,
const char *url,
int do_malloc);
/**
* Share a defined proxy worker via shm
* @param worker worker to be shared
* @param shm location of shared info
* @param i index into shm
* @return APR_SUCCESS or error code
*/
PROXY_DECLARE(apr_status_t) ap_proxy_share_worker(proxy_worker *worker,
proxy_worker_shared *shm,
int i);
/**
* Initialize the worker by setting up worker connection pool and mutex
* @param worker worker to initialize
* @param s current server record
* @param p memory pool used for mutex and connection pool
* @return APR_SUCCESS or error code
*/
PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker,
server_rec *s,
apr_pool_t *p);
/**
* Verifies valid balancer name (eg: balancer://foo)
* @param name name to test
* @param i number of chars to test; 0 for all.
* @return true/false
*/
PROXY_DECLARE(int) ap_proxy_valid_balancer_name(char *name, int i);
/**
* Get the balancer from proxy configuration
* @param p memory pool used for temporary storage while finding balancer
* @param conf current proxy server configuration
* @param url url to find the worker from; must have balancer:// prefix
* @param careactive true if we care if the balancer is active or not
* @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,
int careactive);
/**
* Update the balancer's vhost related fields
* @param p memory pool used for temporary storage while finding balancer
* @param balancer balancer to be updated
* @param url url to find vhost info
* @return error string or NULL if OK
*/
PROXY_DECLARE(char *) ap_proxy_update_balancer(apr_pool_t *p,
proxy_balancer *balancer,
const char *url);
/**
* Define and Allocate space for the balancer to proxy configuration
* @param p memory pool to allocate balancer from
* @param balancer the new balancer
* @param conf current proxy server configuration
* @param url url containing balancer name
* @param alias alias/fake-path to this balancer
* @param do_malloc true if shared struct should be malloced
* @return error message or NULL if successfull
*/
PROXY_DECLARE(char *) ap_proxy_define_balancer(apr_pool_t *p,
proxy_balancer **balancer,
proxy_server_conf *conf,
const char *url,
const char *alias,
int do_malloc);
/**
* Share a defined proxy balancer via shm
* @param balancer balancer to be shared
* @param shm location of shared info
* @param i index into shm
* @return APR_SUCCESS or error code
*/
PROXY_DECLARE(apr_status_t) ap_proxy_share_balancer(proxy_balancer *balancer,
proxy_balancer_shared *shm,
int i);
/**
* Initialize the balancer as needed
* @param balancer balancer to initialize
* @param s current server record
* @param p memory pool used for mutex and connection pool
* @return APR_SUCCESS or error code
*/
PROXY_DECLARE(apr_status_t) ap_proxy_initialize_balancer(proxy_balancer *balancer,
server_rec *s,
apr_pool_t *p);
/**
* Find the shm of the worker as needed
* @param storage slotmem provider
* @param slot slotmem instance
* @param worker worker to find
* @param index pointer to index within slotmem of worker
* @return pointer to shm of worker, or NULL
*/
PROXY_DECLARE(proxy_worker_shared *) ap_proxy_find_workershm(ap_slotmem_provider_t *storage,
ap_slotmem_instance_t *slot,
proxy_worker *worker,
unsigned int *index);
/**
* Find the shm of the balancer as needed
* @param storage slotmem provider
* @param slot slotmem instance
* @param balancer balancer of shm to find
* @param index pointer to index within slotmem of balancer
* @return pointer to shm of balancer, or NULL
*/
PROXY_DECLARE(proxy_balancer_shared *) ap_proxy_find_balancershm(ap_slotmem_provider_t *storage,
ap_slotmem_instance_t *slot,
proxy_balancer *balancer,
unsigned int *index);
/**
* 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 Whenever 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);
/**
* Determine 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 a proxy
* @param proxyport proxy host port
* @param server_portstr Via headers server port, must be non-NULL
* @param server_portstr_size size of the server_portstr buffer; must
* be at least one, even if the protocol doesn't use this
* @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 worker worker used for retrying
* @param s current server record
* @return OK if marked for retry, DECLINED otherwise
* @note The error status of the worker will cleared if the retry interval has
* elapsed since the last error.
*/
APR_DECLARE_OPTIONAL_FN(int, ap_proxy_retry_worker,
(const char *proxy_function, proxy_worker *worker, server_rec *s));
/**
* Acquire a connection from worker 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 connection limit has been reached, the function will
* block until a connection becomes available or the timeout has
* elapsed.
*/
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 to a Unix Domain Socket (UDS) path
* @param sock UDS to connect
* @param uds_path UDS path to connect to
* @param p pool to make the sock addr
* @return APR_SUCCESS or error status
*/
PROXY_DECLARE(apr_status_t) ap_proxy_connect_uds(apr_socket_t *sock,
const char *uds_path,
apr_pool_t *p);
/**
* 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
* @note The function will return immediately if conn->connection
* is already set,
*/
PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function,
proxy_conn_rec *conn,
conn_rec *c, server_rec *s);
/**
* Determine if proxy connection can potentially be reused at the
* end of this request.
* @param conn proxy connection
* @return non-zero if reusable, 0 otherwise
* @note Even if this function returns non-zero, the connection may
* be subsequently marked for closure.
*/
PROXY_DECLARE(int) ap_proxy_connection_reusable(proxy_conn_rec *conn);
/**
* Signal the upstream chain that the connection to the backend broke in the
* middle of the response. This is done by sending an error bucket with
* status HTTP_BAD_GATEWAY and an EOS bucket up the filter chain.
* @param r current request record of client request
* @param brigade The brigade that is sent through the output filter chain
*/
PROXY_DECLARE(void) ap_proxy_backend_broke(request_rec *r,
apr_bucket_brigade *brigade);
/**
* Return a hash based on the passed string
* @param str string to produce hash from
* @param method hashing method to use
* @return hash as unsigned int
*/
typedef enum { PROXY_HASHFUNC_DEFAULT, PROXY_HASHFUNC_APR, PROXY_HASHFUNC_FNV } proxy_hash_t;
PROXY_DECLARE(unsigned int) ap_proxy_hashfunc(const char *str, proxy_hash_t method);
/**
* Set/unset the worker status bitfield depending on flag
* @param c flag
* @param set set or unset bit
* @param w worker to use
* @return APR_SUCCESS if valid flag
*/
PROXY_DECLARE(apr_status_t) ap_proxy_set_wstatus(char c, int set, proxy_worker *w);
/**
* Create readable representation of worker status bitfield
* @param p pool
* @param w worker to use
* @return string representation of status
*/
PROXY_DECLARE(char *) ap_proxy_parse_wstatus(apr_pool_t *p, proxy_worker *w);
/**
* Sync balancer and workers based on any updates w/i shm
* @param b balancer to check/update member list of
* @param s server rec
* @param conf config
* @return APR_SUCCESS if all goes well
*/
PROXY_DECLARE(apr_status_t) ap_proxy_sync_balancer(proxy_balancer *b,
server_rec *s,
proxy_server_conf *conf);
/**
* Find the matched alias for this request and setup for proxy handler
* @param r request
* @param ent proxy_alias record
* @param dconf per-dir config or NULL
* @return DECLINED, DONE or OK if matched
*/
PROXY_DECLARE(int) ap_proxy_trans_match(request_rec *r,
struct proxy_alias *ent,
proxy_dir_conf *dconf);
/**
* Create a HTTP request header brigade, old_cl_val and old_te_val as required.
* @param p pool
* @param header_brigade header brigade to use/fill
* @param r request
* @param p_conn proxy connection rec
* @param worker selected worker
* @param conf per-server proxy config
* @param uri uri
* @param url url
* @param server_portstr port as string
* @param old_cl_val stored old content-len val
* @param old_te_val stored old TE val
* @return OK or HTTP_EXPECTATION_FAILED
*/
PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
apr_bucket_brigade *header_brigade,
request_rec *r,
proxy_conn_rec *p_conn,
proxy_worker *worker,
proxy_server_conf *conf,
apr_uri_t *uri,
char *url, char *server_portstr,
char **old_cl_val,
char **old_te_val);
/**
* @param bucket_alloc bucket allocator
* @param r request
* @param p_conn proxy connection
* @param origin connection rec of origin
* @param bb brigade to send to origin
* @param flush flush
* @return status (OK)
*/
PROXY_DECLARE(int) ap_proxy_pass_brigade(apr_bucket_alloc_t *bucket_alloc,
request_rec *r, proxy_conn_rec *p_conn,
conn_rec *origin, apr_bucket_brigade *bb,
int flush);
/**
* Clear the headers referenced by the Connection header from the given
* table, and remove the Connection header.
* @param r request
* @param headers table of headers to clear
* @return 1 if "close" was present, 0 otherwise.
*/
APR_DECLARE_OPTIONAL_FN(int, ap_proxy_clear_connection,
(request_rec *r, apr_table_t *headers));
#define PROXY_LBMETHOD "proxylbmethod"
/* 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 maximum number of workers in scoreboard.
* @return number of workers to allocate in the scoreboard
*/
int ap_proxy_lb_workers(void);
/**
* Return the port number of a known scheme (eg: http -> 80).
* @param scheme scheme to test
* @return port number or 0 if unknown
*/
PROXY_DECLARE(apr_port_t) ap_proxy_port_of_scheme(const char *scheme);
/**
* Strip a unix domain socket (UDS) prefix from the input URL
* @param p pool to allocate result from
* @param url a URL potentially prefixed with a UDS path
* @return URL with the UDS prefix removed
*/
PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url);
/*
* Transform buckets from one bucket allocator to another one by creating a
* transient bucket for each data bucket and let it use the data read from
* the old bucket. Metabuckets are transformed by just recreating them.
* Attention: Currently only the following bucket types are handled:
*
* All data buckets
* FLUSH
* EOS
*
* If an other bucket type is found its type is logged as a debug message
* and APR_EGENERAL is returned.
*
* @param r request_rec of the actual request. Used for logging purposes
* @param from the bucket brigade to take the buckets from
* @param to the bucket brigade to store the transformed buckets
* @return apr_status_t of the operation. Either APR_SUCCESS or
* APR_EGENERAL
*/
PROXY_DECLARE(apr_status_t) ap_proxy_buckets_lifetime_transform(request_rec *r,
apr_bucket_brigade *from,
apr_bucket_brigade *to);
/*
* Sends all data that can be read non blocking from the input filter chain of
* c_i and send it down the output filter chain of c_o. For reading it uses
* the bucket brigade bb_i which should be created from the bucket allocator
* associated with c_i. For sending through the output filter chain it uses
* the bucket brigade bb_o which should be created from the bucket allocator
* associated with c_o. In order to get the buckets from bb_i to bb_o
* ap_proxy_buckets_lifetime_transform is used.
*
* @param r request_rec of the actual request. Used for logging purposes
* @param c_i inbound connection conn_rec
* @param c_o outbound connection conn_rec
* @param bb_i bucket brigade for pulling data from the inbound connection
* @param bb_o bucket brigade for sending data through the outbound connection
* @param name string for logging from where data was pulled
* @param sent if not NULL will be set to 1 if data was sent through c_o
* @param bsize maximum amount of data pulled in one iteration from c_i
* @param after if set flush data on c_o only once after the loop
* @return apr_status_t of the operation. Could be any error returned from
* either the input filter chain of c_i or the output filter chain
* of c_o. APR_EPIPE if the outgoing connection was aborted.
*/
PROXY_DECLARE(apr_status_t) ap_proxy_transfer_between_connections(
request_rec *r,
conn_rec *c_i,
conn_rec *c_o,
apr_bucket_brigade *bb_i,
apr_bucket_brigade *bb_o,
const char *name,
int *sent,
apr_off_t bsize,
int after);
extern module PROXY_DECLARE_DATA proxy_module;
#endif /*MOD_PROXY_H*/
/** @} */