mod_proxy.h revision 8b1e99bce759689078370bcfb2d9f98c668baba2
/* 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
*
*
* 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"
#endif
#endif
/* for proxy_canonenc() */
enum enctype {
};
#define BALANCER_PREFIX "balancer://"
#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 */
int use_regex; /* simple boolean. True if we have a regex pattern */
};
#define PROXYPASS_NOCANON 0x01
#define PROXYPASS_INTERPOLATE 0x02
#define PROXYPASS_NOQUERY 0x04
struct proxy_alias {
const char *real;
const char *fake;
unsigned int flags;
};
struct dirconn_entry {
char *name;
struct apr_sockaddr_t *hostaddr;
};
struct noproxy_entry {
const char *name;
struct apr_sockaddr_t *addr;
};
typedef struct {
const char *domain; /* domain name to use in absence of a domain name in the request */
const char *id;
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 {
} viaopt; /* how to deal with proxy Via: headers */
long maxfwd;
enum {
} badopt; /* how to deal with bad headers */
enum {
} proxy_status; /* Status display options */
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;
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:
*/
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 */
/* if we interpolate env vars per-request, we'll need a per-request
* copy of the reverse proxy config
*/
typedef struct {
typedef struct {
request_rec *r; /* Request record of the backend request
* that is used over the backend connection. */
const char *hostname;
void *data; /* per scheme connection data */
void *forward; /* opaque forward proxy data */
unsigned int is_ssl:1;
* filter chain or not */
const char *uds_path; /* Unix domain socket path */
const char *ssl_hostname;/* Hostname (SNI) in use by SSL connection */
typedef struct {
float cache_completion; /* completion percentage */
int content_length; /* length of the content */
/* Connection pool */
struct proxy_conn_pool {
};
/* 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 | \
/* NOTE: these check the shared status */
/* 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 96
#define PROXY_BALANCER_MAX_ROUTE_SIZE 64
#define PROXY_WORKER_MAX_NAME_SIZE 256
#define PROXY_BALANCER_MAX_NAME_SIZE 64
#define PROXY_WORKER_MAX_HOSTNAME_SIZE 96
#define PROXY_BALANCER_MAX_HOSTNAME_SIZE 64
#define PROXY_BALANCER_MAX_STICKY_SIZE 64
#define PROXY_MAX_PROVIDER_NAME_SIZE 16
#define PROXY_COPY_CONF_PARAMS(w, c) \
do { \
(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 */
typedef struct {
char name[PROXY_WORKER_MAX_NAME_SIZE];
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 */
unsigned int status; /* worker status bitfield */
enum {
} flush_packets; /* control AJP flushing */
* may be available while exceeding the soft limit */
apr_interval_time_t acquire; /* acquire timeout when the maximum number of connections is exceeded */
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;
unsigned int is_name_matchable:1;
/* Worker configuration */
struct proxy_worker {
unsigned int local_status; /* status of per-process worker */
proxy_worker_shared *s; /* Shared data */
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 name[PROXY_BALANCER_MAX_NAME_SIZE];
int max_attempts; /* Number of attempts before failing */
int index; /* shm array index */
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 */
unsigned int forcerecovery_set:1;
unsigned int scolonsep_set:1;
unsigned int sticky_force_set:1;
unsigned int nonce_set:1;
unsigned int sticky_separator_set:1;
struct proxy_balancer {
int growth; /* number of post-config workers can added */
int max_workers; /* maximum number of allowed workers */
void *context; /* general purpose storage */
proxy_balancer_shared *s; /* Shared data */
int failontimeout; /* Whether to mark a member in Err if IO timeout occurs */
unsigned int failontimeout_set:1;
unsigned int growth_set:1;
unsigned int lbmethod_set:1;
};
struct proxy_balancer_method {
const char *name; /* name of the load balancer method*/
request_rec *r);
void *context; /* general purpose storage */
};
#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_DATA
#elif defined(PROXY_DECLARE_STATIC)
#define PROXY_DECLARE_DATA
#elif defined(PROXY_DECLARE_EXPORT)
#else
#endif
char *url))
/**
* Let modules perform processing when the connection to the origin is being
* detached from the request.
* @param r The client request
* @param backend The proxy representation of the backend connection
*/
/**
* pre request hook.
* It will return the most suitable worker at the moment
* and coresponding balancer.
* and then the scheme_handler is called.
*
*/
request_rec *r,
/**
* post request hook.
* It is called after request for updating runtime balancer status.
*/
/**
* 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
*/
(int *status, request_rec *r))
/* proxy_util.c */
PROXY_DECLARE(int) ap_proxy_hex2c(const char *x);
* 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
*/
/* 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 *);
request_rec *r);
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)
proxy_dir_conf *, const char *);
#elif defined(PROXY_DECLARE_EXPORT)
typedef __declspec(dllexport) const char *
proxy_dir_conf *, const char *);
#else
typedef __declspec(dllimport) const char *
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
*/
/**
* 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
*/
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)
*/
const char *url,
int do_malloc);
/**
* Define and Allocate space for the ap_strcmp_match()able 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 (produces match pattern)
* @param do_malloc true if shared struct should be malloced
* @return error message or NULL if successful (*worker is new worker)
*/
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
*/
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
*/
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.
*/
/**
* 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
*/
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
*/
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 do_malloc true if shared struct should be malloced
* @return error message or NULL if successfull
*/
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
*/
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
*/
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
*/
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
*/
unsigned int *index);
/**
* @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
*/
request_rec *r,
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.
*/
request_rec *r,
/**
* 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
*/
char **url,
const char *proxyname,
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.
*/
/**
* 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.
*/
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
*/
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.
*/
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
*/
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,
*/
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.
*/
/**
* 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
* @deprecated To be removed in v2.6.
*/
/**
* 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
*/
/**
* @param c flag
* @param set set or unset bit
* @param w worker to use
* @return APR_SUCCESS if valid flag
*/
/**
* Create readable representation of worker status bitfield
* @param p pool
* @param w worker to use
* @return string representation of status
*/
/**
* Sync balancer and workers based on any updates w/i shm
* @param s server rec
* @param conf config
* @return APR_SUCCESS if all goes well
*/
server_rec *s,
/**
* 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
*/
struct proxy_alias *ent,
/**
* Create a HTTP request header brigade, old_cl_val and old_te_val as required.
* @param p pool
* @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
*/
request_rec *r,
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)
*/
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.
*/
/**
* @param socket socket to test
*/
#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
*/
/**
* 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
*/
#endif /*MOD_PROXY_H*/
/** @} */