#include "mod_proxy.h"
#include "http_main.h"
#include "ap_md5.h"
#include "multithread.h"
#include "http_log.h"
#include "util_uri.h"
#include "util_date.h" /* get ap_checkmask() decl. */
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);
static
struct
per_thread_data *get_per_thread_data(
void
);
int
ap_proxy_hex2c(
const
char
*x)
{
int
i, ch;
#ifndef CHARSET_EBCDIC
ch = x[0];
if
(ap_isdigit(ch))
i = ch -
'0'
;
else
if
(ap_isupper(ch))
i = ch - (
'A'
- 10);
else
i = ch - (
'a'
- 10);
i <<= 4;
ch = x[1];
if
(ap_isdigit(ch))
i += ch -
'0'
;
else
if
(ap_isupper(ch))
i += ch - (
'A'
- 10);
else
i += ch - (
'a'
- 10);
return
i;
#else /*CHARSET_EBCDIC*/
return
(1 ==
sscanf
(x,
"%2x"
, &i)) ? os_toebcdic[i&0xFF] : 0;
#endif /*CHARSET_EBCDIC*/
}
void
ap_proxy_c2hex(
int
ch,
char
*x)
{
#ifndef 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 /*CHARSET_EBCDIC*/
static
const
char
ntoa[] = {
"0123456789ABCDEF"
};
ch = os_toascii[ch & 0xFF];
x[0] =
'%'
;
x[1] = ntoa[(ch>>4)&0x0F];
x[2] = ntoa[ch&0x0F];
x[3] =
'\0'
;
#endif /*CHARSET_EBCDIC*/
}
char
*ap_proxy_canonenc(pool *p,
const
char
*x,
int
len,
enum
enctype t,
enum
proxyreqtype isenc)
{
int
i, j, ch;
char
*y;
const
char
*allowed;
const
char
*reserved;
if
(t == enc_path)
allowed =
"$-_.+!*'(),;:@&="
;
else
if
(t == enc_search)
allowed =
"$-_.!*'(),;:@&="
;
else
if
(t == enc_user)
allowed =
"$-_.+!*'(),;@&="
;
else
if
(t == enc_fpath)
allowed =
"$-_.+!*'(),?:@&="
;
else
allowed =
"$-_.+!*'(),?/:@&="
;
if
(t == enc_path)
reserved =
"/"
;
else
if
(t == enc_search)
reserved =
"+"
;
else
reserved =
""
;
y = ap_palloc(p, 3 * len + 1);
for
(i = 0, j = 0; i < len; i++, j++) {
ch = x[i];
if
(
strchr
(reserved, ch)) {
y[j] = ch;
continue
;
}
if
(isenc != NOT_PROXY && ch ==
'%'
) {
if
(!ap_isxdigit(x[i + 1]) || !ap_isxdigit(x[i + 2]))
return
NULL;
ch = ap_proxy_hex2c(&x[i + 1]);
i += 2;
if
(ch != 0 &&
strchr
(reserved, ch)) {
ap_proxy_c2hex(ch, &y[j]);
j += 2;
continue
;
}
}
if
(!ap_isalnum(ch) && !
strchr
(allowed, ch)) {
ap_proxy_c2hex(ch, &y[j]);
j += 2;
}
else
y[j] = ch;
}
y[j] =
'\0'
;
return
y;
}
char
*
ap_proxy_canon_netloc(pool *p,
char
**
const
urlp,
char
**userp,
char
**passwordp,
char
**hostp,
int
*port)
{
int
i;
char
*strp, *host, *url = *urlp;
char
*user = NULL, *password = NULL;
if
(url[0] !=
'/'
|| url[1] !=
'/'
)
return
"Malformed URL"
;
host = url + 2;
url =
strchr
(host,
'/'
);
if
(url == NULL)
url =
""
;
else
*(url++) =
'\0'
;
strp =
strrchr
(host,
'@'
);
if
(strp != NULL) {
*strp =
'\0'
;
user = host;
host = strp + 1;
strp =
strchr
(user,
':'
);
if
(strp != NULL) {
*strp =
'\0'
;
password = ap_proxy_canonenc(p, strp + 1,
strlen
(strp + 1), enc_user, STD_PROXY);
if
(password == NULL)
return
"Bad %-escape in URL (password)"
;
}
user = ap_proxy_canonenc(p, user,
strlen
(user), enc_user, STD_PROXY);
if
(user == NULL)
return
"Bad %-escape in URL (username)"
;
}
if
(userp != NULL) {
*userp = user;
}
if
(passwordp != NULL) {
*passwordp = password;
}
strp =
strrchr
(host,
':'
);
if
(strp != NULL) {
*(strp++) =
'\0'
;
for
(i = 0; strp[i] !=
'\0'
; i++)
if
(!ap_isdigit(strp[i]))
break
;
if
(strp[i] !=
'\0'
) {
return
"Bad port number in URL"
;
}
else
if
(i > 0) {
*port =
atoi
(strp);
if
(*port > 65535)
return
"Port number in URL > 65535"
;
}
}
ap_str_tolower(host);
if
(*host ==
'\0'
)
return
"Missing host in URL"
;
for
(i = 0; host[i] !=
'\0'
; i++)
if
(!ap_isdigit(host[i]) && host[i] !=
'.'
)
break
;
#if defined(WIN32) || defined(NETWARE) || defined(TPF) || defined(BEOS)
if
(host[i] ==
'\0'
&& (inet_addr(host) == -1))
#else
if
(host[i] ==
'\0'
&& (ap_inet_addr(host) == -1 || inet_network(host) == -1))
#endif
{
return
"Bad IP address in URL"
;
}
*urlp = url;
*hostp = host;
return
NULL;
}
static
const
char
*
const
lwday[7] =
{
"Sunday"
,
"Monday"
,
"Tuesday"
,
"Wednesday"
,
"Thursday"
,
"Friday"
,
"Saturday"
};
const
char
*
ap_proxy_date_canon(pool *p,
const
char
*x)
{
int
wk, mday, year, hour, min, sec, mon;
char
*q, month[4], zone[4], week[4];
q =
strchr
(x,
','
);
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;
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
{
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, ap_day_snames[wk]) == 0)
break
;
if
(wk == 7)
return
x;
}
for
(mon = 0; mon < 12; mon++)
if
(
strcmp
(month, ap_month_snames[mon]) == 0)
break
;
if
(mon == 12)
return
x;
q = ap_palloc(p, 30);
ap_snprintf(q, 30,
"%s, %.2d %s %d %.2d:%.2d:%.2d GMT"
, ap_day_snames[wk], mday,
ap_month_snames[mon], year, hour, min, sec);
return
q;
}
static
int
proxy_getline(
char
*s,
int
n, BUFF *in,
int
fold)
{
char
*pos, next;
int
retval;
int
total = 0;
pos = s;
do
{
retval = ap_bgets(pos, n, in);
if
(retval <= 0)
return
((retval < 0) && (total == 0)) ? -1 : total;
n -= retval;
pos += (retval - 1);
total += retval;
if
(*pos ==
'\n'
) {
*pos =
'\0'
;
--total;
++n;
}
else
return
total;
}
while
(fold && (retval != 1) && (n > 1)
&& (ap_blookc(&next, in) == 1)
&& ((next ==
' '
) || (next ==
'\t'
)));
return
total;
}
table *ap_proxy_read_headers(request_rec *r,
char
*buffer,
int
size, BUFF *f)
{
table *resp_hdrs;
int
len;
char
*value, *end;
char
field[MAX_STRING_LEN];
resp_hdrs = ap_make_table(r->pool, 20);
while
((len = proxy_getline(buffer, size, f, 1)) > 0) {
if
(!(value =
strchr
(buffer,
':'
))) {
if
(!ap_checkmask(buffer,
"HTTP/#.# ###*"
)) {
return
NULL;
}
ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, r->server,
"proxy: Ignoring duplicate HTTP header "
"returned by %s (%s)"
, r->uri, r->method);
continue
;
}
*value =
'\0'
;
++value;
while
(ap_isspace(*value))
++value;
for
(end = &value[
strlen
(value)-1]; end > value && ap_isspace(*end); --end)
*end =
'\0'
;
ap_table_add(resp_hdrs, buffer, value);
if
(len >= size - 1) {
while
((len = proxy_getline(field, MAX_STRING_LEN, f, 1))
>= MAX_STRING_LEN - 1) {
}
if
(len == 0)
break
;
}
}
return
resp_hdrs;
}
long
int
ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c, off_t len,
int
nowrite)
{
int
ok;
char
buf[IOBUFSIZE];
long
total_bytes_rcvd;
register
int
n, o, w;
conn_rec *con = r->connection;
int
alternate_timeouts = 1;
total_bytes_rcvd = 0;
if
(c != NULL)
c->written = 0;
#ifdef CHARSET_EBCDIC
ap_bsetflag(f, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0);
if
(c != NULL && c->fp != NULL)
ap_bsetflag(c->fp, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0);
ap_bsetflag(con->client, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0);
#endif
ap_kill_timeout(r);
#if defined(WIN32) || defined(TPF) || defined(NETWARE)
ap_hard_timeout(
"proxy send body"
, r);
alternate_timeouts = 0;
#else
if
(c == NULL || c->len <= 0 || c->cache_completion == 1.0) {
ap_hard_timeout(
"proxy send body"
, r);
alternate_timeouts = 0;
}
#endif
for
(ok = 1; ok; ) {
if
(alternate_timeouts)
ap_hard_timeout(
"proxy recv body from upstream server"
, r);
if
(-1 == len) {
n = ap_bread(f, buf, IOBUFSIZE);
}
else
{
n = ap_bread(f, buf, MIN(IOBUFSIZE, len - total_bytes_rcvd));
}
if
(alternate_timeouts)
ap_kill_timeout(r);
else
ap_reset_timeout(r);
if
(n == -1) {
if
(c != NULL) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
"proxy: error reading from %s"
, c->url);
c = ap_proxy_cache_error(c);
}
break
;
}
if
(n == 0)
break
;
o = 0;
total_bytes_rcvd += n;
if
(c != NULL && c->fp != NULL) {
if
(ap_bwrite(c->fp, &buf[0], n) != n) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
"proxy: error writing to %s"
, c->tempfile);
c = ap_proxy_cache_error(c);
}
else
{
c->written += n;
}
}
while
(!nowrite && !con->aborted && n > 0) {
if
(alternate_timeouts)
ap_soft_timeout(
"proxy send body"
, r);
w = ap_bwrite(con->client, &buf[o], n);
if
(alternate_timeouts)
ap_kill_timeout(r);
else
ap_reset_timeout(r);
if
(w <= 0) {
if
(c != NULL) {
ok = (c->len > 0) &&
(c->cache_completion > 0) &&
(c->len * c->cache_completion < total_bytes_rcvd);
if
(! ok) {
if
(c->fp!=NULL) {
ap_pclosef(c->req->pool, ap_bfileno(c->fp, B_WR));
c->fp = NULL;
}
unlink(c->tempfile);
c = NULL;
}
}
con->aborted = 1;
break
;
}
n -= w;
o += w;
}
if
(total_bytes_rcvd == len)
break
;
}
if
(!con->aborted)
ap_bflush(con->client);
ap_kill_timeout(r);
return
total_bytes_rcvd;
}
void
ap_proxy_write_headers(cache_req *c,
const
char
*respline, table *t)
{
if
(respline && c->fp != NULL &&
ap_bvputs(c->fp, respline, CRLF, NULL) == -1) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
"proxy: error writing status line to %s"
, c->tempfile);
c = ap_proxy_cache_error(c);
return
;
}
ap_table_do(ap_proxy_send_hdr_line, c, t, NULL);
if
(c->fp != NULL && ap_bputs(CRLF, c->fp) == -1) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
"proxy: error writing CRLF to %s"
, c->tempfile);
c = ap_proxy_cache_error(c);
}
}
int
ap_proxy_liststr(
const
char
*list,
const
char
*key,
char
**val)
{
int
len, i;
const
char
*p;
char
valbuf[HUGE_STRING_LEN];
valbuf[
sizeof
(valbuf)-1] = 0;
len =
strlen
(key);
while
(list != NULL) {
p =
strchr
(list,
','
);
if
(p != NULL) {
i = p - list;
do
p++;
while
(ap_isspace(*p));
}
else
i =
strlen
(list);
while
(i > 0 && ap_isspace(list[i - 1]))
i--;
if
(i == len && strncasecmp(list, key, len) == 0) {
if
(val) {
p =
strchr
(list,
','
);
while
(ap_isspace(*list)) {
list++;
}
if
(
'='
== list[0])
list++;
while
(ap_isspace(*list)) {
list++;
}
strncpy
(valbuf, list, MIN(p-list,
sizeof
(valbuf)-1));
*val = valbuf;
}
return
1;
}
list = p;
}
return
0;
}
#ifdef CASE_BLIND_FILESYSTEM
void
ap_proxy_hash(
const
char
*it,
char
*val,
int
ndepth,
int
nlength)
{
AP_MD5_CTX context;
unsigned
char
digest[16];
char
tmp[26];
int
i, k, d;
unsigned
int
x;
static
const
char
enc_table[32] =
"abcdefghijklmnopqrstuvwxyz012345"
;
ap_MD5Init(&context);
ap_MD5Update(&context, (
const
unsigned
char
*) it,
strlen
(it));
ap_MD5Final(digest, &context);
for
(i = 0, k = 0; i < 15; i += 5) {
x = (digest[i] << 24) | (digest[i + 1] << 16) | (digest[i + 2] << 8) | digest[i + 3];
tmp[k++] = enc_table[x >> 27];
tmp[k++] = enc_table[(x >> 22) & 0x1f];
tmp[k++] = enc_table[(x >> 17) & 0x1f];
tmp[k++] = enc_table[(x >> 12) & 0x1f];
tmp[k++] = enc_table[(x >> 7) & 0x1f];
tmp[k++] = enc_table[(x >> 2) & 0x1f];
x = ((x & 0x3) << 8) | digest[i + 4];
tmp[k++] = enc_table[x >> 5];
tmp[k++] = enc_table[x & 0x1f];
}
x = digest[15];
tmp[k++] = enc_table[x >> 3];
tmp[k++] = enc_table[x & 0x7];
for
(i = k = d = 0; d < ndepth; ++d) {
memcpy
(&val[i], &tmp[k], nlength);
k += nlength;
val[i + nlength] =
'/'
;
i += nlength + 1;
}
memcpy
(&val[i], &tmp[k], 26 - k);
val[i + 26 - k] =
'\0'
;
}
#else
void
ap_proxy_hash(
const
char
*it,
char
*val,
int
ndepth,
int
nlength)
{
AP_MD5_CTX context;
unsigned
char
digest[16];
char
tmp[22];
int
i, k, d;
unsigned
int
x;
#if defined(MPE) || (defined(AIX) && defined(__ps2__))
static
const
char
enc_table[64] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_%"
;
#else
static
const
char
enc_table[64] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_@"
;
#endif
ap_MD5Init(&context);
ap_MD5Update(&context, (
const
unsigned
char
*) it,
strlen
(it));
ap_MD5Final(digest, &context);
for
(i = 0, k = 0; i < 15; i += 3) {
x = (digest[i] << 16) | (digest[i + 1] << 8) | digest[i + 2];
tmp[k++] = enc_table[x >> 18];
tmp[k++] = enc_table[(x >> 12) & 0x3f];
tmp[k++] = enc_table[(x >> 6) & 0x3f];
tmp[k++] = enc_table[x & 0x3f];
}
x = digest[15];
tmp[k++] = enc_table[x >> 2];
tmp[k++] = enc_table[(x << 4) & 0x3f];
for
(i = k = d = 0; d < ndepth; ++d) {
memcpy
(&val[i], &tmp[k], nlength);
k += nlength;
val[i + nlength] =
'/'
;
i += nlength + 1;
}
memcpy
(&val[i], &tmp[k], 22 - k);
val[i + 22 - k] =
'\0'
;
}
#endif /* CASE_BLIND_FILESYSTEM */
int
ap_proxy_hex2sec(
const
char
*x)
{
int
i, ch;
unsigned
int
j;
for
(i = 0, j = 0; i < 16; i++) {
ch = x[i];
j <<= 4;
if
(ap_isdigit(ch))
j |= ch -
'0'
;
else
if
(ap_isupper(ch))
j |= ch - (
'A'
- 10);
else
j |= ch - (
'a'
- 10);
}
return
j;
}
void
ap_proxy_sec2hex(
int
t,
char
*y)
{
int
i, ch;
unsigned
int
j = t;
if
(-1 == t) {
strcpy
(y,
"FFFFFFFFFFFFFFFF"
);
return
;
}
for
(i = 15; i >= 0; i--) {
ch = j & 0xF;
j >>= 4;
if
(ch >= 10)
y[i] = ch + (
'A'
- 10);
else
y[i] = ch +
'0'
;
}
y[16] =
'\0'
;
}
cache_req *ap_proxy_cache_error(cache_req *c)
{
if
(c != NULL) {
if
(c->fp != NULL) {
ap_pclosef(c->req->pool, ap_bfileno(c->fp, B_WR));
c->fp = NULL;
}
if
(c->origfp != NULL) {
ap_pclosef(c->req->pool, ap_bfileno(c->origfp, B_WR));
c->origfp = NULL;
}
if
(c->tempfile)
unlink(c->tempfile);
}
return
NULL;
}
int
ap_proxyerror(request_rec *r,
int
statuscode,
const
char
*message)
{
ap_table_setn(r->notes,
"error-notes"
,
ap_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),
" "
,
ap_escape_html(r->pool, r->uri),
"</A></EM>.<P>\n"
"Reason: <STRONG>"
,
ap_escape_html(r->pool, message),
"</STRONG>"
, NULL));
ap_table_setn(r->notes,
"verbose-error-to"
, ap_pstrdup(r->pool,
"*"
));
r->status_line = ap_psprintf(r->pool,
"%3.3u Proxy Error"
, statuscode);
return
statuscode;
}
const
char
*
ap_proxy_host2addr(
const
char
*host,
struct
hostent *reqhp)
{
int
i;
struct
hostent *hp;
struct
per_thread_data *ptd = get_per_thread_data();
for
(i = 0; host[i] !=
'\0'
; i++)
if
(!ap_isdigit(host[i]) && host[i] !=
'.'
)
break
;
if
(host[i] !=
'\0'
) {
hp = gethostbyname(host);
if
(hp == NULL)
return
"Host not found"
;
}
else
{
ptd->ipaddr = ap_inet_addr(host);
hp = gethostbyaddr((
char
*) &ptd->ipaddr,
sizeof
(ptd->ipaddr), AF_INET);
if
(hp == NULL) {
memset
(&ptd->hpbuf, 0,
sizeof
(ptd->hpbuf));
ptd->hpbuf.h_name = 0;
ptd->hpbuf.h_addrtype = AF_INET;
ptd->hpbuf.h_length =
sizeof
(ptd->ipaddr);
ptd->hpbuf.h_addr_list = ptd->charpbuf;
ptd->hpbuf.h_addr_list[0] = (
char
*) &ptd->ipaddr;
ptd->hpbuf.h_addr_list[1] = 0;
hp = &ptd->hpbuf;
}
}
*reqhp = *hp;
return
NULL;
}
static
const
char
*
proxy_get_host_of_request(request_rec *r)
{
char
*url, *user = NULL, *password = NULL, *err, *host;
int
port = -1;
if
(r->hostname != NULL)
return
r->hostname;
if
((url =
strchr
(r->uri,
':'
)) == NULL
|| url[1] !=
'/'
|| url[2] !=
'/'
)
return
NULL;
url = ap_pstrdup(r->pool, &url[1]);
err = ap_proxy_canon_netloc(r->pool, &url, &user, &password, &host, &port);
if
(err != NULL)
ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r,
"%s"
, err);
r->hostname = host;
return
host;
}
int
ap_proxy_is_ipaddr(
struct
dirconn_entry *This, pool *p)
{
const
char
*addr = This->name;
long
ip_addr[4];
int
i, quads;
long
bits;
for
(quads = 0; quads < 4 && *addr !=
'\0'
; ++quads) {
char
*tmp;
if
(*addr ==
'/'
&& quads > 0)
break
;
if
(!ap_isdigit(*addr))
return
0;
ip_addr[quads] =
strtol
(addr, &tmp, 0);
if
(tmp == addr)
return
0;
if
(ip_addr[quads] < 0 || ip_addr[quads] > 255) {
return
0;
}
addr = tmp;
if
(*addr ==
'.'
&& quads != 3)
++addr;
}
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] ==
'/'
&& ap_isdigit(addr[1])) {
char
*tmp;
++addr;
bits =
strtol
(addr, &tmp, 0);
if
(tmp == addr)
return
0;
addr = tmp;
if
(bits < 0 || bits > 32)
return
0;
}
else
{
while
(quads > 0 && ip_addr[quads - 1] == 0)
--quads;
if
(quads < 1)
return
0;
bits = 8 * quads;
if
(bits != 32)
fprintf
(stderr,
"Warning: NetMask not supplied with IP-Addr; guessing: %s/%ld\n"
,
inet_ntoa(This->addr), bits);
}
This->mask.s_addr = htonl(INADDR_NONE << (32 - bits));
if
(*addr ==
'\0'
&& (This->addr.s_addr & ~This->mask.s_addr) != 0) {
fprintf
(stderr,
"Warning: NetMask and IP-Addr disagree in %s/%ld\n"
,
inet_ntoa(This->addr), bits);
This->addr.s_addr &= This->mask.s_addr;
fprintf
(stderr,
" Set to %s/%ld\n"
,
inet_ntoa(This->addr), bits);
}
if
(*addr ==
'\0'
) {
This->matcher = proxy_match_ipaddr;
return
1;
}
else
return
(*addr ==
'\0'
);
}
static
int
proxy_match_ipaddr(
struct
dirconn_entry *This, request_rec *r)
{
int
i;
int
ip_addr[4];
struct
in_addr addr;
struct
in_addr *ip_list;
char
**ip_listptr;
const
char
*found;
const
char
*host = proxy_get_host_of_request(r);
if
(host == NULL)
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
fprintf
(stderr,
"1)IP-Match: %s[%s] <-> "
, host, inet_ntoa(addr));
fprintf
(stderr,
"%s/"
, inet_ntoa(This->addr));
fprintf
(stderr,
"%s\n"
, inet_ntoa(This->mask));
#endif
return
1;
}
#if DEBUGGING
else
{
fprintf
(stderr,
"1)IP-NoMatch: %s[%s] <-> "
, host, inet_ntoa(addr));
fprintf
(stderr,
"%s/"
, inet_ntoa(This->addr));
fprintf
(stderr,
"%s\n"
, inet_ntoa(This->mask));
}
#endif
}
else
{
struct
hostent the_host;
memset
(&the_host,
'\0'
,
sizeof
the_host);
found = ap_proxy_host2addr(host, &the_host);
if
(found != NULL) {
#if DEBUGGING
fprintf
(stderr,
"2)IP-NoMatch: hostname=%s msg=%s\n"
, host, found);
#endif
return
0;
}
if
(the_host.h_name != NULL)
found = the_host.h_name;
else
found = host;
for
(ip_listptr = the_host.h_addr_list; *ip_listptr; ++ip_listptr) {
ip_list = (
struct
in_addr *) *ip_listptr;
if
(This->addr.s_addr == (ip_list->s_addr & This->mask.s_addr)) {
#if DEBUGGING
fprintf
(stderr,
"3)IP-Match: %s[%s] <-> "
, found, inet_ntoa(*ip_list));
fprintf
(stderr,
"%s/"
, inet_ntoa(This->addr));
fprintf
(stderr,
"%s\n"
, inet_ntoa(This->mask));
#endif
return
1;
}
#if DEBUGGING
else
{
fprintf
(stderr,
"3)IP-NoMatch: %s[%s] <-> "
, found, inet_ntoa(*ip_list));
fprintf
(stderr,
"%s/"
, inet_ntoa(This->addr));
fprintf
(stderr,
"%s\n"
, inet_ntoa(This->mask));
}
#endif
}
}
return
0;
}
int
ap_proxy_is_domainname(
struct
dirconn_entry *This, pool *p)
{
char
*addr = This->name;
int
i;
if
(addr[0] !=
'.'
)
return
0;
for
(i = 0; ap_isalnum(addr[i]) || addr[i] ==
'-'
|| addr[i] ==
'.'
; ++i)
continue
;
#if 0
if
(addr[i] ==
':'
) {
fprintf
(stderr,
"@@@@ handle optional port in proxy_is_domainname()\n"
);
}
#endif
if
(addr[i] !=
'\0'
)
return
0;
for
(i =
strlen
(addr) - 1; i > 0 && addr[i] ==
'.'
; --i)
addr[i] =
'\0'
;
This->matcher = proxy_match_domainname;
return
1;
}
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)
return
0;
h_len =
strlen
(host);
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;
}
int
ap_proxy_is_hostname(
struct
dirconn_entry *This, pool *p)
{
struct
hostent host;
char
*addr = This->name;
int
i;
if
(addr[0] ==
'.'
)
return
0;
for
(i = 0; ap_isalnum(addr[i]) || addr[i] ==
'-'
|| addr[i] ==
'.'
; ++i);
#if 0
if
(addr[i] ==
':'
) {
fprintf
(stderr,
"@@@@ handle optional port in proxy_is_hostname()\n"
);
}
#endif
if
(addr[i] !=
'\0'
|| ap_proxy_host2addr(addr, &host) != NULL)
return
0;
This->hostentry = ap_pduphostent (p, &host);
for
(i =
strlen
(addr) - 1; i > 0 && addr[i] ==
'.'
; --i)
addr[i] =
'\0'
;
This->matcher = proxy_match_hostname;
return
1;
}
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;
h2_len =
strlen
(host2);
h1_len =
strlen
(host);
#if 0
unsigned
long
*ip_list;
for
(ip_list = *This->hostentry->h_addr_list; *ip_list != 0UL; ++ip_list)
if
(*ip_list == ? ? ? ? ? ? ? ? ? ? ? ? ?)
return
1;
#endif
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;
}
int
ap_proxy_is_word(
struct
dirconn_entry *This, pool *p)
{
This->matcher = proxy_match_word;
return
1;
}
static
int
proxy_match_word(
struct
dirconn_entry *This, request_rec *r)
{
const
char
*host = proxy_get_host_of_request(r);
return
host != NULL &&
strstr
(host, This->name) != NULL;
}
int
ap_proxy_doconnect(
int
sock,
struct
sockaddr_in *addr, request_rec *r)
{
int
i;
ap_hard_timeout(
"proxy connect"
, r);
do
{
i = connect(sock, (
struct
sockaddr *) addr,
sizeof
(
struct
sockaddr_in));
#if defined(WIN32) || defined(NETWARE)
if
(i == SOCKET_ERROR)
errno
= WSAGetLastError();
#endif /* WIN32 */
}
while
(i == -1 &&
errno
== EINTR);
if
(i == -1) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
"proxy connect to %s port %d failed"
,
inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
}
ap_kill_timeout(r);
return
i;
}
int
ap_proxy_send_hdr_line(
void
*p,
const
char
*key,
const
char
*value)
{
cache_req *c = (cache_req *)p;
if
(key == NULL || value == NULL || value[0] ==
'\0'
)
return
1;
if
(c->fp != NULL &&
ap_bvputs(c->fp, key,
": "
, value, CRLF, NULL) == -1) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
"proxy: error writing header to %s"
, c->tempfile);
c = ap_proxy_cache_error(c);
return
0;
}
return
1;
}
unsigned ap_proxy_bputs2(
const
char
*data, BUFF *client, cache_req *cache)
{
unsigned len = ap_bputs(data, client);
if
(cache != NULL && cache->fp != NULL)
ap_bputs(data, cache->fp);
return
len;
}
time_t
ap_proxy_current_age(cache_req *c,
const
time_t
age_value)
{
time_t
apparent_age, corrected_received_age, response_delay, corrected_initial_age, resident_time, current_age;
apparent_age = MAX(0, c->resp_time - c->date);
corrected_received_age = MAX(apparent_age, age_value);
response_delay = c->resp_time - c->req_time;
corrected_initial_age = corrected_received_age + response_delay;
resident_time =
time
(NULL) - c->resp_time;
current_age = corrected_initial_age + resident_time;
return
(current_age);
}
BUFF *ap_proxy_open_cachefile(request_rec *r,
char
*filename)
{
BUFF *cachefp = NULL;
int
cfd;
if
(filename != NULL) {
cfd = open(filename, O_RDWR | O_BINARY);
if
(cfd != -1) {
ap_note_cleanups_for_fd(r->pool, cfd);
cachefp = ap_bcreate(r->pool, B_RD | B_WR);
ap_bpushfd(cachefp, cfd, cfd);
}
else
if
(
errno
!= ENOENT)
ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
"proxy: error opening cache file %s"
,
filename);
else
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r->server,
"File %s not found"
, filename);
}
return
cachefp;
}
BUFF *ap_proxy_create_cachefile(request_rec *r,
char
*filename)
{
BUFF *cachefp = NULL;
int
cfd;
if
(filename != NULL) {
cfd = open(filename, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0622);
if
(cfd != -1) {
ap_note_cleanups_for_fd(r->pool, cfd);
cachefp = ap_bcreate(r->pool, B_WR);
ap_bpushfd(cachefp, -1, cfd);
}
else
if
(
errno
!= ENOENT)
ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
"proxy: error creating cache file %s"
,
filename);
}
return
cachefp;
}
void
ap_proxy_clear_connection(pool *p, table *headers)
{
const
char
*name;
char
*next = ap_pstrdup(p, ap_table_get(headers,
"Connection"
));
ap_table_unset(headers,
"Proxy-Connection"
);
if
(!next)
return
;
while
(*next) {
name = next;
while
(*next && !ap_isspace(*next) && (*next !=
','
))
++next;
while
(*next && (ap_isspace(*next) || (*next ==
','
))) {
*next =
'\0'
;
++next;
}
ap_table_unset(headers, name);
}
ap_table_unset(headers,
"Connection"
);
}
int
ap_proxy_table_replace(table *base, table *overlay)
{
table_entry *elts = (table_entry *) overlay->a.elts;
int
i, q = 0;
const
char
*val;
for
(i = 0; i < overlay->a.nelts; ++i) {
val = ap_table_get(base, elts[i].key);
if
(!val ||
strcmp
(val, elts[i].val))
q = 1;
ap_table_set(base, elts[i].key, elts[i].val);
}
return
q;
}
#if defined WIN32
static
DWORD
tls_index;
BOOL
WINAPI DllMain (
HINSTANCE
dllhandle,
DWORD
reason,
LPVOID
reserved)
{
LPVOID
memptr;
switch
(reason) {
case
DLL_PROCESS_ATTACH:
tls_index = TlsAlloc();
case
DLL_THREAD_ATTACH:
TlsSetValue (tls_index,
malloc
(
sizeof
(
struct
per_thread_data)));
break
;
case
DLL_THREAD_DETACH:
memptr = TlsGetValue (tls_index);
if
(memptr) {
free
(memptr);
TlsSetValue (tls_index, 0);
}
break
;
}
return
TRUE;
}
#endif
static
struct
per_thread_data *get_per_thread_data(
void
)
{
#if defined(WIN32)
return
(
struct
per_thread_data *) TlsGetValue (tls_index);
#else
static
APACHE_TLS
struct
per_thread_data sptd;
return
&sptd;
#endif
}