proxy_util.c revision 983528026996668ea295be95aedb9c7a346af470
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele/* Licensed to the Apache Software Foundation (ASF) under one or more
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele * contributor license agreements. See the NOTICE file distributed with
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele * this work for additional information regarding copyright ownership.
5f5d1b4cc970b7f06ff8ef6526128e9a27303d88nd * The ASF licenses this file to You under the Apache License, Version 2.0
acc36ab93565d2880447d535da6ca6e5feac7a70nd * (the "License"); you may not use this file except in compliance with
acc36ab93565d2880447d535da6ca6e5feac7a70nd * the License. You may obtain a copy of the License at
db479b48bd4d75423ed4a45e15b75089d1a8ad72fielding * Unless required by applicable law or agreed to in writing, software
db479b48bd4d75423ed4a45e15b75089d1a8ad72fielding * distributed under the License is distributed on an "AS IS" BASIS,
db479b48bd4d75423ed4a45e15b75089d1a8ad72fielding * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
acc36ab93565d2880447d535da6ca6e5feac7a70nd * See the License for the specific language governing permissions and
acc36ab93565d2880447d535da6ca6e5feac7a70nd * limitations under the License.
acc36ab93565d2880447d535da6ca6e5feac7a70nd/* Utility routines for Apache proxy */
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen#include "apr_support.h" /* for apr_wait_for_io_or_timeout() */
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele * Opaque structure containing target server info when
19e48954d3cfb4f573a99866b0071b6aaa62723ckess * using a forward proxy.
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen * Up to now only used in combination with HTTP CONNECT.
252b32956857ad89fc9ee708c4c6eb36097a647cerikabeletypedef struct {
e50df6c711553f98103f1e0802f7de8c59be7cddslive int use_http_connect; /* Use SSL Tunneling via HTTP CONNECT */
e50df6c711553f98103f1e0802f7de8c59be7cddslive/* Keep synced with mod_proxy.h! */
e50df6c711553f98103f1e0802f7de8c59be7cddslivestatic struct wstat {
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele unsigned int bit;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele const char *name;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele {PROXY_WORKER_INITIALIZED, PROXY_WORKER_INITIALIZED_FLAG, "Init "},
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele {PROXY_WORKER_IGNORE_ERRORS, PROXY_WORKER_IGNORE_ERRORS_FLAG, "Ign "},
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele {PROXY_WORKER_DRAIN, PROXY_WORKER_DRAIN_FLAG, "Drn "},
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele {PROXY_WORKER_IN_SHUTDOWN, PROXY_WORKER_IN_SHUTDOWN_FLAG, "Shut "},
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele {PROXY_WORKER_DISABLED, PROXY_WORKER_DISABLED_FLAG, "Dis "},
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen {PROXY_WORKER_STOPPED, PROXY_WORKER_STOPPED_FLAG, "Stop "},
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele {PROXY_WORKER_IN_ERROR, PROXY_WORKER_IN_ERROR_FLAG, "Err "},
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele {PROXY_WORKER_HOT_STANDBY, PROXY_WORKER_HOT_STANDBY_FLAG, "Stby "},
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele {PROXY_WORKER_FREE, PROXY_WORKER_FREE_FLAG, "Free "},
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen/* Global balancer counter */
e50df6c711553f98103f1e0802f7de8c59be7cddslivestatic int lb_workers_limit = 0;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabeleconst apr_strmatch_pattern PROXY_DECLARE_DATA *ap_proxy_strmatch_path;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabeleconst apr_strmatch_pattern PROXY_DECLARE_DATA *ap_proxy_strmatch_domain;
252b32956857ad89fc9ee708c4c6eb36097a647cerikabelestatic int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r);
252b32956857ad89fc9ee708c4c6eb36097a647cerikabelestatic int proxy_match_domainname(struct dirconn_entry *This, request_rec *r);
19e48954d3cfb4f573a99866b0071b6aaa62723ckessstatic int proxy_match_hostname(struct dirconn_entry *This, request_rec *r);
cf02129aebf73dd0bdf369b172eb481ff76ac5f6colmstatic int proxy_match_word(struct dirconn_entry *This, request_rec *r);
e50df6c711553f98103f1e0802f7de8c59be7cddsliveAPR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, create_req,
e50df6c711553f98103f1e0802f7de8c59be7cddslivePROXY_DECLARE(apr_status_t) ap_proxy_strncpy(char *dst, const char *src,
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele /* special case handling */
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele /* XXX: APR_ENOSPACE would be better */
e50df6c711553f98103f1e0802f7de8c59be7cddslive/* already called in the knowledge that the characters are hex digits */
19e48954d3cfb4f573a99866b0071b6aaa62723ckess int ch = x[0];
e50df6c711553f98103f1e0802f7de8c59be7cddslive#else /*APR_CHARSET_EBCDIC*/
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen * we assume that the hex value refers to an ASCII character
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele * so convert to EBCDIC so that it makes sense locally;
e50df6c711553f98103f1e0802f7de8c59be7cddslive * client specifies %20 in URL to refer to a space char;
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen * at this point we're called with EBCDIC "20"; after turning
e50df6c711553f98103f1e0802f7de8c59be7cddslive * EBCDIC "20" into binary 0x20, we then need to assume that 0x20
e50df6c711553f98103f1e0802f7de8c59be7cddslive * represents an ASCII char and convert 0x20 to EBCDIC, yielding
e50df6c711553f98103f1e0802f7de8c59be7cddslive return buf[0];
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele#endif /*APR_CHARSET_EBCDIC*/
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen x[0] = '%';
91dbfe27f56a07b53ec19068fdb47581476d5c3brbowen if (i >= 10) {
e50df6c711553f98103f1e0802f7de8c59be7cddslive if (i >= 10) {
e50df6c711553f98103f1e0802f7de8c59be7cddslive#else /*APR_CHARSET_EBCDIC*/
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele#endif /*APR_CHARSET_EBCDIC*/
e50df6c711553f98103f1e0802f7de8c59be7cddslive * canonicalise a URL-encoded string
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele * Convert a URL-encoded string to canonical form.
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele * It decodes characters which need not be encoded,
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele * and encodes those which must be encoded, and does not touch
e50df6c711553f98103f1e0802f7de8c59be7cddslive * those which must not be touched.
252b32956857ad89fc9ee708c4c6eb36097a647cerikabelePROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len,
19e48954d3cfb4f573a99866b0071b6aaa62723ckess char *allowed; /* characters which should not be encoded */
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele char *reserved; /* characters which much not be en/de-coded */
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele * N.B. in addition to :@&=, this allows ';' in an http path
f50095bc3874806a9cc5e7d283dd9051ef8a0df8nd * and '?' in an ftp path -- this may be revised
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele * Also, it makes a '+' character in a search string reserved, as
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele * it may be form-encoded. (Although RFC 1738 doesn't allow this -
252b32956857ad89fc9ee708c4c6eb36097a647cerikabele * it only permits ; / ? : @ = & as reserved chars.)
if (t == enc_path) {
else if (t == enc_search) {
else if (t == enc_user) {
else if (t == enc_fpath) {
if (t == enc_path) {
else if (t == enc_search) {
for (i = 0, j = 0; i < len; i++, j++) {
ch = x[i];
y[j] = ch;
return NULL;
y[j] = ch;
PROXY_DECLARE(char *)
return NULL;
NULL));
r->uri);
return statuscode;
return r->hostname;
return NULL;
url = apr_pstrdup(r->pool, &url[1]); /* make it point to "//", which is what proxy_canon_netloc expects */
int i, quads;
long bits;
char *tmp;
char *tmp;
++addr;
--quads;
/* "IP Address should be given in dotted-quad form, optionally followed by a netmask (e.g., 192.168.111.0/24)"; */
#if DEBUGGING
#if DEBUGGING
!= APR_SUCCESS) {
#if DEBUGGING
while (reqaddr) {
#if DEBUGGING
#if DEBUGGING
--d_len;
--h_len;
int h2_len;
int h1_len;
while (addr) {
--h2_len;
--h1_len;
return HTTP_FORBIDDEN;
if (!addr)
return HTTP_FORBIDDEN;
return OK;
return OK;
return url;
int n, l3 = 0;
if (urlpart) {
* BalancerMember balancer://alias http://example.com/foo
* translate url http://example.com/foo/bar/that to /bash/that
if (urlpart) {
--l2;
NULL);
worker++;
if (part) {
if (part) {
return url;
&proxy_module);
const char *pathp;
const char *domainp;
int ddiff = 0;
int pdiff = 0;
char *ret;
return str;
if (newpath) {
if (newdomain) {
if (newdomain) {
return ret;
const char *url,
int care)
return NULL;
return balancer;
balancer++;
return NULL;
const char *url)
if (!url) {
return NULL;
return NULL;
const char *url,
const char *alias,
int do_malloc)
const char *sname;
if (do_malloc)
&sname);
return APR_EINVAL;
if (lbmethod) {
return APR_EINVAL;
return rv;
PROXY_DECLARE(apr_status_t) ap_proxy_initialize_balancer(proxy_balancer *balancer, server_rec *s, apr_pool_t *p)
unsigned int num;
if (!storage) {
return APR_EGENERAL;
return APR_EGENERAL;
return rv;
return APR_EGENERAL;
return rv;
return APR_SUCCESS;
return APR_SUCCESS;
return APR_SUCCESS;
if (conn->r) {
return APR_SUCCESS;
apr_pool_clear(p);
return APR_SUCCESS;
request_rec *r)
return APR_SUCCESS;
return APR_SUCCESS;
return APR_SUCCESS;
const char *url)
int max_match = 0;
int url_length;
int min_match;
int worker_name_length;
char *url_copy;
if (!url) {
return NULL;
return NULL;
char *pathstart;
if (balancer) {
return max_worker;
const char *url,
int do_malloc)
int rv;
* require format: unix:/path/foo/bar.sock|http://ignored/path2/
if (ptr) {
if (sockpath) {
* ProxyPass / http://www.example.com
if (balancer) {
} else if (conf) {
if (do_malloc)
if (sockpath) {
return NULL;
return APR_EINVAL;
if (pool) {
return APR_SUCCESS;
PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, server_rec *s, apr_pool_t *p)
int mpm_threads;
return rv;
return APR_EGENERAL;
void *conn;
return rv;
server_rec *s)
return OK;
return DECLINED;
return OK;
request_rec *r,
int access_status;
if (*worker) {
char *ptr;
char *ptr2;
return access_status;
request_rec *r,
if (balancer) {
return access_status;
const char *proxy_function,
const char *backend_name,
request_rec *r)
int connected = 0;
int loglevel;
server_rec *s)
return HTTP_SERVICE_UNAVAILABLE;
return HTTP_SERVICE_UNAVAILABLE;
return OK;
server_rec *s)
return OK;
PROXY_DECLARE(int)
char **url,
const char *proxyname,
char *server_portstr,
int server_portstr_size)
int server_port;
const char *uds_path;
NULL));
if (!proxyname) {
if (uds_path) {
if (proxyname) {
const char *proxy_auth;
if (!will_reuse) {
if (will_reuse) {
return HTTP_INTERNAL_SERVER_ERROR;
const char *ssl_hostname;
ssl_hostname) != 0)) ||
return OK;
server_rec *s)
int status;
int complete = 0;
int len = 0;
if (!complete) {
buffer);
code_str);
return(status);
const char *uds_path,
apr_pool_t *p)
return rv;
return rv;
return rv;
return APR_SUCCESS;
server_rec *s)
int connected = 0;
int loglevel;
sizeof(apr_sockaddr_t));
if (!c->aborted) {
if (saved_timeout) {
(void)ap_shutdown_conn(c, 0);
if (saved_timeout) {
return APR_SUCCESS;
conn_rec *c,
server_rec *s)
int rc;
return OK;
0, NULL,
return HTTP_INTERNAL_SERVER_ERROR;
return HTTP_INTERNAL_SERVER_ERROR;
return rc;
return OK;
int ap_proxy_lb_workers(void)
if (!lb_workers_limit)
return lb_workers_limit;
apr_bucket *e;
if (r->main)
c->bucket_alloc);
PROXY_DECLARE(unsigned int)
unsigned int hash;
return hash;
unsigned int hash;
return hash;
if (set)
return APR_SUCCESS;
pwt++;
return APR_EINVAL;
pwt++;
if (PROXY_WORKER_IS_USABLE(w))
return ret;
int index;
return APR_SUCCESS;
if (lbmethod) {
return APR_EINVAL;
int found;
return APR_EGENERAL;
found = 0;
if (!found) {
return rv;
if (b->s->need_reset) {
b->s->need_reset = 0;
return APR_SUCCESS;
unsigned int *index)
unsigned int i, limit;
for (i = 0; i < limit; i++) {
return NULL;
*index = i;
return shm;
return NULL;
unsigned int *index)
unsigned int i, limit;
for (i = 0; i < limit; i++) {
return NULL;
*index = i;
return shm;
return NULL;
typedef struct header_connection {
const char *first;
const char *name;
val++;
if (!x->first) {
const char **elt;
if (!x->array) {
} while (*val);
const char **name;
x.closed = 0;
if (x.first) {
if (x.array) {
return x.closed;
request_rec *r,
char **old_cl_val,
char **old_te_val)
int counter;
char *buf;
apr_bucket *e;
int do_100_continue;
const char *fpr1;
&& !(fpr1)
&& ap_request_has_body(r));
if (fpr1) {
if (r->expecting_100) {
return HTTP_EXPECTATION_FAILED;
if (!hostname) {
if (do_100_continue) {
const char *val;
if (!r->expecting_100) {
const char *buf;
r->useragent_ip);
proxy_run_fixups(r);
if (r->main) {
NULL);
return OK;
int flush)
if (flush) {
const char *ssl_note;
return HTTP_GATEWAY_TIME_OUT;
return HTTP_BAD_REQUEST;
return OK;
typedef struct proxy_schemes_t {
const char *name;
} proxy_schemes_t ;
if (scheme) {
return port;