proxy_util.c revision c6cf638d68b4cfff4f74ebc360abca97ad38cd71
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/* Licensed to the Apache Software Foundation (ASF) under one or more
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * contributor license agreements. See the NOTICE file distributed with
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * this work for additional information regarding copyright ownership.
bc8fd1b0b1afdf89b8d28eefa8cd74e26ba97986fielding * The ASF licenses this file to You under the Apache License, Version 2.0
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * (the "License"); you may not use this file except in compliance with
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * the License. You may obtain a copy of the License at
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb *
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * http://www.apache.org/licenses/LICENSE-2.0
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb *
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * Unless required by applicable law or agreed to in writing, software
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * distributed under the License is distributed on an "AS IS" BASIS,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * See the License for the specific language governing permissions and
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * limitations under the License.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/* Utility routines for Apache proxy */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#include "mod_proxy.h"
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#include "ap_mpm.h"
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#include "scoreboard.h"
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#include "apr_version.h"
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#if APR_HAVE_UNISTD_H
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#include <unistd.h> /* for getpid() */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#endif
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#if (APR_MAJOR_VERSION < 1)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#undef apr_socket_create
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#define apr_socket_create apr_socket_create_ex
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#endif
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbAPLOG_USE_MODULE(proxy);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * Opaque structure containing target server info when
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * using a forward proxy.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * Up to now only used in combination with HTTP CONNECT.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbtypedef struct {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int use_http_connect; /* Use SSL Tunneling via HTTP CONNECT */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb const char *target_host; /* Target hostname */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb apr_port_t target_port; /* Target port */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb const char *proxy_auth; /* Proxy authorization */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb} forward_info;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/* Global balancer counter */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbint PROXY_DECLARE_DATA proxy_lb_workers = 0;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic int lb_workers_limit = 0;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic int proxy_match_domainname(struct dirconn_entry *This, request_rec *r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic int proxy_match_hostname(struct dirconn_entry *This, request_rec *r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic int proxy_match_word(struct dirconn_entry *This, request_rec *r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbAPR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, create_req,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb (request_rec *r, request_rec *pr), (r, pr),
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb OK, DECLINED)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/* already called in the knowledge that the characters are hex digits */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbPROXY_DECLARE(int) ap_proxy_hex2c(const char *x)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int i, ch;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#if !APR_CHARSET_EBCDIC
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ch = x[0];
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (apr_isdigit(ch)) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb i = ch - '0';
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else if (apr_isupper(ch)) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb i = ch - ('A' - 10);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb i = ch - ('a' - 10);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb i <<= 4;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ch = x[1];
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (apr_isdigit(ch)) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb i += ch - '0';
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else if (apr_isupper(ch)) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb i += ch - ('A' - 10);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb i += ch - ('a' - 10);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
f888346b48f5e5b5e3f0a47dedb8cefd2759a4e2gregames return i;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#else /*APR_CHARSET_EBCDIC*/
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * we assume that the hex value refers to an ASCII character
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * so convert to EBCDIC so that it makes sense locally;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb *
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * example:
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb *
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * client specifies %20 in URL to refer to a space char;
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz * at this point we're called with EBCDIC "20"; after turning
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz * EBCDIC "20" into binary 0x20, we then need to assume that 0x20
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz * represents an ASCII char and convert 0x20 to EBCDIC, yielding
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz * 0x40
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz */
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz char buf[1];
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz if (1 == sscanf(x, "%2x", &i)) {
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz buf[0] = i & 0xFF;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_xlate_proto_from_ascii(buf, 1);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return buf[0];
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
4f9c22c4f27571d54197be9674e1fc0d528192aestriker else {
a2a0abd88b19e042a3eb2a9fa1702c25ad51303dwrowe return 0;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#endif /*APR_CHARSET_EBCDIC*/
4f9c22c4f27571d54197be9674e1fc0d528192aestriker}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
4f9c22c4f27571d54197be9674e1fc0d528192aestrikerPROXY_DECLARE(void) ap_proxy_c2hex(int ch, char *x)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
4f9c22c4f27571d54197be9674e1fc0d528192aestriker#if !APR_CHARSET_EBCDIC
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int i;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb x[0] = '%';
4f9c22c4f27571d54197be9674e1fc0d528192aestriker i = (ch & 0xF0) >> 4;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (i >= 10) {
4f9c22c4f27571d54197be9674e1fc0d528192aestriker x[1] = ('A' - 10) + i;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else {
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe x[1] = '0' + i;
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe }
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe i = ch & 0x0F;
2d399cd7535887fceaa9f8f116eb98ce68ddd602trawick if (i >= 10) {
c2cf53a40a9814eb91db2cdf820f97d943f21628coar x[2] = ('A' - 10) + i;
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe }
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe else {
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar x[2] = '0' + i;
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe }
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar#else /*APR_CHARSET_EBCDIC*/
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe static const char ntoa[] = { "0123456789ABCDEF" };
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe char buf[1];
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe ch &= 0xFF;
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe buf[0] = ch;
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe ap_xlate_proto_to_ascii(buf, 1);
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe x[0] = '%';
3e392a5afd51526de3cb15d57ee46d8cb160ae65gregames x[1] = ntoa[(buf[0] >> 4) & 0x0F];
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe x[2] = ntoa[buf[0] & 0x0F];
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe x[3] = '\0';
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe#endif /*APR_CHARSET_EBCDIC*/
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe}
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz/*
2a6e98ba4ffa30ded5d8831664c5cb2a170a56b6coar * canonicalise a URL-encoded string
2a6e98ba4ffa30ded5d8831664c5cb2a170a56b6coar */
2a6e98ba4ffa30ded5d8831664c5cb2a170a56b6coar
2a6e98ba4ffa30ded5d8831664c5cb2a170a56b6coar/*
2a6e98ba4ffa30ded5d8831664c5cb2a170a56b6coar * Convert a URL-encoded string to canonical form.
2a6e98ba4ffa30ded5d8831664c5cb2a170a56b6coar * It decodes characters which need not be encoded,
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz * and encodes those which must be encoded, and does not touch
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz * those which must not be touched.
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe */
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowePROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len,
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe enum enctype t, int forcedec,
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe int proxyreq)
4f9c22c4f27571d54197be9674e1fc0d528192aestriker{
4f9c22c4f27571d54197be9674e1fc0d528192aestriker int i, j, ch;
3e392a5afd51526de3cb15d57ee46d8cb160ae65gregames char *y;
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe char *allowed; /* characters which should not be encoded */
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar char *reserved; /* characters which much not be en/de-coded */
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe/*
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe * N.B. in addition to :@&=, this allows ';' in an http path
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe * and '?' in an ftp path -- this may be revised
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe *
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe * Also, it makes a '+' character in a search string reserved, as
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe * it may be form-encoded. (Although RFC 1738 doesn't allow this -
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe * it only permits ; / ? : @ = & as reserved chars.)
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe */
4f9c22c4f27571d54197be9674e1fc0d528192aestriker if (t == enc_path) {
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe allowed = "~$-_.+!*'(),;:@&=";
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe }
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe else if (t == enc_search) {
c2cf53a40a9814eb91db2cdf820f97d943f21628coar allowed = "$-_.!*'(),;:@&=";
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe }
4775dfc34c90fada8c7c4d6a57ed8a3114d55c2dtrawick else if (t == enc_user) {
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe allowed = "$-_.+!*'(),;@&=";
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe }
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe else if (t == enc_fpath) {
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe allowed = "$-_.+!*'(),?:@&=";
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar }
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe else { /* if (t == enc_parm) */
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe allowed = "$-_.+!*'(),?/:@&=";
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe }
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe if (t == enc_path) {
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe reserved = "/";
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe }
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe else if (t == enc_search) {
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe reserved = "+";
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe }
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe else {
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe reserved = "";
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe }
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe y = apr_palloc(p, 3 * len + 1);
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe for (i = 0, j = 0; i < len; i++, j++) {
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe/* always handle '/' first */
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe ch = x[i];
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe if (strchr(reserved, ch)) {
4f9c22c4f27571d54197be9674e1fc0d528192aestriker y[j] = ch;
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe continue;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker }
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe/*
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * decode it if not already done. do not decode reverse proxied URLs
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe * unless specifically forced
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe */
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar if ((forcedec || (proxyreq && proxyreq != PROXYREQ_REVERSE)) && ch == '%') {
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe if (!apr_isxdigit(x[i + 1]) || !apr_isxdigit(x[i + 2])) {
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe return NULL;
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe }
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe ch = ap_proxy_hex2c(&x[i + 1]);
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe i += 2;
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe if (ch != 0 && strchr(reserved, ch)) { /* keep it encoded */
4f9c22c4f27571d54197be9674e1fc0d528192aestriker ap_proxy_c2hex(ch, &y[j]);
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe j += 2;
c2cf53a40a9814eb91db2cdf820f97d943f21628coar continue;
c2cf53a40a9814eb91db2cdf820f97d943f21628coar }
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe }
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz/* recode it, if necessary */
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz if (!apr_isalnum(ch) && !strchr(allowed, ch)) {
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz ap_proxy_c2hex(ch, &y[j]);
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe j += 2;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker }
c2cf53a40a9814eb91db2cdf820f97d943f21628coar else {
c2cf53a40a9814eb91db2cdf820f97d943f21628coar y[j] = ch;
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe }
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz }
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz y[j] = '\0';
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz return y;
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe}
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe/*
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * Parses network-location.
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe * urlp on input the URL; on output the path, after the leading /
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * user NULL if no user/password permitted
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * password holder for password
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe * host holder for host
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe * port port number; only set if one is supplied.
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz *
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz * Returns an error string.
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz */
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowePROXY_DECLARE(char *)
4f9c22c4f27571d54197be9674e1fc0d528192aestriker ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp,
c2cf53a40a9814eb91db2cdf820f97d943f21628coar char **passwordp, char **hostp, apr_port_t *port)
c2cf53a40a9814eb91db2cdf820f97d943f21628coar{
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe char *addr, *scope_id, *strp, *host, *url = *urlp;
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz char *user = NULL, *password = NULL;
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz apr_port_t tmp_port;
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz apr_status_t rv;
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe
4f9c22c4f27571d54197be9674e1fc0d528192aestriker if (url[0] != '/' || url[1] != '/') {
c2cf53a40a9814eb91db2cdf820f97d943f21628coar return "Malformed URL";
c2cf53a40a9814eb91db2cdf820f97d943f21628coar }
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe host = url + 2;
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz url = strchr(host, '/');
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz if (url == NULL) {
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz url = "";
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe }
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe else {
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe *(url++) = '\0'; /* skip seperating '/' */
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe }
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe /* find _last_ '@' since it might occur in user/password part */
4f9c22c4f27571d54197be9674e1fc0d528192aestriker strp = strrchr(host, '@');
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe if (strp != NULL) {
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe *strp = '\0';
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz user = host;
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe host = strp + 1;
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe/* find password */
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe strp = strchr(user, ':');
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe if (strp != NULL) {
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe *strp = '\0';
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe password = ap_proxy_canonenc(p, strp + 1, strlen(strp + 1), enc_user, 1, 0);
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe if (password == NULL) {
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe return "Bad %-escape in URL (password)";
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe }
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe }
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe user = ap_proxy_canonenc(p, user, strlen(user), enc_user, 1, 0);
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe if (user == NULL) {
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe return "Bad %-escape in URL (username)";
4f9c22c4f27571d54197be9674e1fc0d528192aestriker }
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe }
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe if (userp != NULL) {
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe *userp = user;
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe }
0540a0b469147b52e858587270dba31c2aaa9e09wrowe if (passwordp != NULL) {
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe *passwordp = password;
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe }
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe /*
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe * Parse the host string to separate host portion from optional port.
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * Perform range checking on port.
4f9c22c4f27571d54197be9674e1fc0d528192aestriker */
4f9c22c4f27571d54197be9674e1fc0d528192aestriker rv = apr_parse_addr_port(&addr, &scope_id, &tmp_port, host, p);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker if (rv != APR_SUCCESS || addr == NULL || scope_id != NULL) {
4f9c22c4f27571d54197be9674e1fc0d528192aestriker return "Invalid host/port";
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe }
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe if (tmp_port != 0) { /* only update caller's port if port was specified */
a2b181763cb35fd899feb4a436aeadaa80bf91eabrianp *port = tmp_port;
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe }
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe
a2b181763cb35fd899feb4a436aeadaa80bf91eabrianp ap_str_tolower(addr); /* DNS names are case-insensitive */
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe *urlp = url;
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe *hostp = addr;
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe return NULL;
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe}
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe
a2b181763cb35fd899feb4a436aeadaa80bf91eabrianp/*
a2b181763cb35fd899feb4a436aeadaa80bf91eabrianp * If the date is a valid RFC 850 date or asctime() date, then it
a2b181763cb35fd899feb4a436aeadaa80bf91eabrianp * is converted to the RFC 1123 format.
a2b181763cb35fd899feb4a436aeadaa80bf91eabrianp */
4f9c22c4f27571d54197be9674e1fc0d528192aestrikerPROXY_DECLARE(const char *)
a2b181763cb35fd899feb4a436aeadaa80bf91eabrianp ap_proxy_date_canon(apr_pool_t *p, const char *date)
a2b181763cb35fd899feb4a436aeadaa80bf91eabrianp{
4f9c22c4f27571d54197be9674e1fc0d528192aestriker apr_status_t rv;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker char* ndate;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
4f9c22c4f27571d54197be9674e1fc0d528192aestriker apr_time_t time = apr_date_parse_http(date);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker if (!time) {
4f9c22c4f27571d54197be9674e1fc0d528192aestriker return date;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker }
a2b181763cb35fd899feb4a436aeadaa80bf91eabrianp
7a2edaa0193cbb0d79a65a8461a609a9402aea49brianp ndate = apr_palloc(p, APR_RFC822_DATE_LEN);
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe rv = apr_rfc822_date(ndate, time);
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe if (rv != APR_SUCCESS) {
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe return date;
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe }
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe return ndate;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker}
a2b181763cb35fd899feb4a436aeadaa80bf91eabrianp
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowePROXY_DECLARE(request_rec *)ap_proxy_make_fake_req(conn_rec *c, request_rec *r)
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe{
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe request_rec *rp = apr_pcalloc(r->pool, sizeof(*r));
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb rp->pool = r->pool;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb rp->status = HTTP_OK;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb rp->headers_in = apr_table_make(r->pool, 50);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb rp->subprocess_env = apr_table_make(r->pool, 50);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb rp->headers_out = apr_table_make(r->pool, 12);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb rp->err_headers_out = apr_table_make(r->pool, 5);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb rp->notes = apr_table_make(r->pool, 5);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb rp->server = r->server;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb rp->proxyreq = r->proxyreq;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb rp->request_time = r->request_time;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb rp->connection = c;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb rp->output_filters = c->output_filters;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb rp->input_filters = c->input_filters;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb rp->proto_output_filters = c->output_filters;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb rp->proto_input_filters = c->input_filters;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb rp->request_config = ap_create_request_config(r->pool);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb proxy_run_create_req(r, rp);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return rp;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * list is a comma-separated list of case-insensitive tokens, with
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * optional whitespace around the tokens.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * The return returns 1 if the token val is found in the list, or 0
2d399cd7535887fceaa9f8f116eb98ce68ddd602trawick * otherwise.
c2cf53a40a9814eb91db2cdf820f97d943f21628coar */
c2cf53a40a9814eb91db2cdf820f97d943f21628coarPROXY_DECLARE(int) ap_proxy_liststr(const char *list, const char *val)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int len, i;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb const char *p;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe len = strlen(val);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe while (list != NULL) {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe p = ap_strchr_c(list, ',');
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe if (p != NULL) {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe i = p - list;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe do {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe p++;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe } while (apr_isspace(*p));
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe }
4f9c22c4f27571d54197be9674e1fc0d528192aestriker else {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe i = strlen(list);
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe }
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe while (i > 0 && apr_isspace(list[i - 1])) {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe i--;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe }
7c301a1818939f85da8f3629cc3e9b5588610ef0jerenkrantz if (i == len && strncasecmp(list, val, len) == 0) {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe return 1;
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar }
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe list = p;
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar }
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe return 0;
7c301a1818939f85da8f3629cc3e9b5588610ef0jerenkrantz}
7c301a1818939f85da8f3629cc3e9b5588610ef0jerenkrantz
7c301a1818939f85da8f3629cc3e9b5588610ef0jerenkrantz/*
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe * list is a comma-separated list of case-insensitive tokens, with
659ad814f714e556bdd03e1d771cba156baab92ewrowe * optional whitespace around the tokens.
659ad814f714e556bdd03e1d771cba156baab92ewrowe * if val appears on the list of tokens, it is removed from the list,
659ad814f714e556bdd03e1d771cba156baab92ewrowe * and the new list is returned.
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe */
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoarPROXY_DECLARE(char *)ap_proxy_removestr(apr_pool_t *pool, const char *list, const char *val)
11fb2f3611e6ff9a541e10b13e3108934f828141gregames{
11fb2f3611e6ff9a541e10b13e3108934f828141gregames int len, i;
11fb2f3611e6ff9a541e10b13e3108934f828141gregames const char *p;
7c301a1818939f85da8f3629cc3e9b5588610ef0jerenkrantz char *new = NULL;
7c301a1818939f85da8f3629cc3e9b5588610ef0jerenkrantz
7c301a1818939f85da8f3629cc3e9b5588610ef0jerenkrantz len = strlen(val);
7c301a1818939f85da8f3629cc3e9b5588610ef0jerenkrantz
4f9c22c4f27571d54197be9674e1fc0d528192aestriker while (list != NULL) {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe p = ap_strchr_c(list, ',');
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe if (p != NULL) {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe i = p - list;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker do {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe p++;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe } while (apr_isspace(*p));
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe }
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar else {
2f1949bb0e3c209db94c8d521cba7380b9d11421trawick i = strlen(list);
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar }
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar while (i > 0 && apr_isspace(list[i - 1])) {
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar i--;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe }
4f9c22c4f27571d54197be9674e1fc0d528192aestriker if (i == len && strncasecmp(list, val, len) == 0) {
4f9c22c4f27571d54197be9674e1fc0d528192aestriker /* do nothing */
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe }
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar else {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe if (new) {
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar new = apr_pstrcat(pool, new, ",", apr_pstrndup(pool, list, i), NULL);
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe }
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar else {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe new = apr_pstrndup(pool, list, i);
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe }
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe }
7c301a1818939f85da8f3629cc3e9b5588610ef0jerenkrantz list = p;
7c301a1818939f85da8f3629cc3e9b5588610ef0jerenkrantz }
7c301a1818939f85da8f3629cc3e9b5588610ef0jerenkrantz return new;
7c301a1818939f85da8f3629cc3e9b5588610ef0jerenkrantz}
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe/*
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe * Converts 8 hex digits to a time integer
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb */
8aefbd756763807188d2e3ce336a8680e4893066wrowePROXY_DECLARE(int) ap_proxy_hex2sec(const char *x)
8aefbd756763807188d2e3ce336a8680e4893066wrowe{
8aefbd756763807188d2e3ce336a8680e4893066wrowe int i, ch;
8aefbd756763807188d2e3ce336a8680e4893066wrowe unsigned int j;
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe for (i = 0, j = 0; i < 8; i++) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe ch = x[i];
8aefbd756763807188d2e3ce336a8680e4893066wrowe j <<= 4;
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (apr_isdigit(ch)) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe j |= ch - '0';
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe else if (apr_isupper(ch)) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe j |= ch - ('A' - 10);
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe else {
8aefbd756763807188d2e3ce336a8680e4893066wrowe j |= ch - ('a' - 10);
a2a0abd88b19e042a3eb2a9fa1702c25ad51303dwrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (j == 0xffffffff) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe return -1; /* so that it works with 8-byte ints */
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
2fa5b5878e7567e2875807c3e2a2b3b0d3ef74bewrowe else {
2fa5b5878e7567e2875807c3e2a2b3b0d3ef74bewrowe return j;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe}
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe/*
dc8692c6c0ca616a09aa12dad005f2ef23baa1a0wrowe * Converts a time integer to 8 hex digits
a8d11d78181478da6a672f7fbc58b8d523351f49wrowe */
4f9c22c4f27571d54197be9674e1fc0d528192aestrikerPROXY_DECLARE(void) ap_proxy_sec2hex(int t, char *y)
23c6309e36a63b13b61c35999c978017521993d6wrowe{
23c6309e36a63b13b61c35999c978017521993d6wrowe int i, ch;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker unsigned int j = t;
23c6309e36a63b13b61c35999c978017521993d6wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe for (i = 7; i >= 0; i--) {
23c6309e36a63b13b61c35999c978017521993d6wrowe ch = j & 0xF;
2d399cd7535887fceaa9f8f116eb98ce68ddd602trawick j >>= 4;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker if (ch >= 10) {
23c6309e36a63b13b61c35999c978017521993d6wrowe y[i] = ch + ('A' - 10);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe else {
8aefbd756763807188d2e3ce336a8680e4893066wrowe y[i] = ch + '0';
cf6ef072483172309861d06e85b1aeff4573c060wrowe }
cf6ef072483172309861d06e85b1aeff4573c060wrowe }
cf6ef072483172309861d06e85b1aeff4573c060wrowe y[8] = '\0';
8aefbd756763807188d2e3ce336a8680e4893066wrowe}
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
4f9c22c4f27571d54197be9674e1fc0d528192aestrikerPROXY_DECLARE(int) ap_proxyerror(request_rec *r, int statuscode, const char *message)
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe{
2d399cd7535887fceaa9f8f116eb98ce68ddd602trawick apr_table_setn(r->notes, "error-notes",
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe apr_pstrcat(r->pool,
4f9c22c4f27571d54197be9674e1fc0d528192aestriker "The proxy server could not handle the request "
a8d11d78181478da6a672f7fbc58b8d523351f49wrowe "<em><a href=\"", ap_escape_html(r->pool, r->uri),
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe "\">", ap_escape_html(r->pool, r->method),
8aefbd756763807188d2e3ce336a8680e4893066wrowe "&nbsp;",
8aefbd756763807188d2e3ce336a8680e4893066wrowe ap_escape_html(r->pool, r->uri), "</a></em>.<p>\n"
cf6ef072483172309861d06e85b1aeff4573c060wrowe "Reason: <strong>",
cf6ef072483172309861d06e85b1aeff4573c060wrowe ap_escape_html(r->pool, message),
cf6ef072483172309861d06e85b1aeff4573c060wrowe "</strong></p>", NULL));
8aefbd756763807188d2e3ce336a8680e4893066wrowe
cf6ef072483172309861d06e85b1aeff4573c060wrowe /* Allow "error-notes" string to be printed by ap_send_error_response() */
cf6ef072483172309861d06e85b1aeff4573c060wrowe apr_table_setn(r->notes, "verbose-error-to", apr_pstrdup(r->pool, "*"));
a2b181763cb35fd899feb4a436aeadaa80bf91eabrianp
cf6ef072483172309861d06e85b1aeff4573c060wrowe r->status_line = apr_psprintf(r->pool, "%3.3u Proxy Error", statuscode);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
cf6ef072483172309861d06e85b1aeff4573c060wrowe "proxy: %s returned by %s", message, r->uri);
cf6ef072483172309861d06e85b1aeff4573c060wrowe return statuscode;
cf6ef072483172309861d06e85b1aeff4573c060wrowe}
cf6ef072483172309861d06e85b1aeff4573c060wrowe
cf6ef072483172309861d06e85b1aeff4573c060wrowestatic const char *
cf6ef072483172309861d06e85b1aeff4573c060wrowe proxy_get_host_of_request(request_rec *r)
cf6ef072483172309861d06e85b1aeff4573c060wrowe{
cf6ef072483172309861d06e85b1aeff4573c060wrowe char *url, *user = NULL, *password = NULL, *err, *host;
cf6ef072483172309861d06e85b1aeff4573c060wrowe apr_port_t port;
69adb3d949e3dd17c0492a01fc2cf298832c7eefwrowe
69adb3d949e3dd17c0492a01fc2cf298832c7eefwrowe if (r->hostname != NULL) {
d75626f0952c6152a99acd013a4f127d46f0f9edtrawick return r->hostname;
d75626f0952c6152a99acd013a4f127d46f0f9edtrawick }
d75626f0952c6152a99acd013a4f127d46f0f9edtrawick
d75626f0952c6152a99acd013a4f127d46f0f9edtrawick /* Set url to the first char after "scheme://" */
d75626f0952c6152a99acd013a4f127d46f0f9edtrawick if ((url = strchr(r->uri, ':')) == NULL || url[1] != '/' || url[2] != '/') {
d75626f0952c6152a99acd013a4f127d46f0f9edtrawick return NULL;
d75626f0952c6152a99acd013a4f127d46f0f9edtrawick }
d75626f0952c6152a99acd013a4f127d46f0f9edtrawick
d75626f0952c6152a99acd013a4f127d46f0f9edtrawick url = apr_pstrdup(r->pool, &url[1]); /* make it point to "//", which is what proxy_canon_netloc expects */
d75626f0952c6152a99acd013a4f127d46f0f9edtrawick
d75626f0952c6152a99acd013a4f127d46f0f9edtrawick err = ap_proxy_canon_netloc(r->pool, &url, &user, &password, &host, &port);
d75626f0952c6152a99acd013a4f127d46f0f9edtrawick
d75626f0952c6152a99acd013a4f127d46f0f9edtrawick if (err != NULL) {
d75626f0952c6152a99acd013a4f127d46f0f9edtrawick ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "%s", err);
cf6ef072483172309861d06e85b1aeff4573c060wrowe }
cf6ef072483172309861d06e85b1aeff4573c060wrowe
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar r->hostname = host;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar return host; /* ought to return the port, too */
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar}
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar/* Return TRUE if addr represents an IP address (or an IP network address) */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowePROXY_DECLARE(int) ap_proxy_is_ipaddr(struct dirconn_entry *This, apr_pool_t *p)
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe{
4f9c22c4f27571d54197be9674e1fc0d528192aestriker const char *addr = This->name;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe long ip_addr[4];
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe int i, quads;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker long bits;
23c6309e36a63b13b61c35999c978017521993d6wrowe
4f9c22c4f27571d54197be9674e1fc0d528192aestriker /*
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * if the address is given with an explicit netmask, use that
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * Due to a deficiency in apr_inet_addr(), it is impossible to parse
c2cf53a40a9814eb91db2cdf820f97d943f21628coar * "partial" addresses (with less than 4 quads) correctly, i.e.
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe * 192.168.123 is parsed as 192.168.0.123, which is not what I want.
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * I therefore have to parse the IP address manually:
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe * if (proxy_readmask(This->name, &This->addr.s_addr, &This->mask.s_addr) == 0)
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe * addr and mask were set by proxy_readmask()
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe * return 1;
a9a4544168a37b43bd180b3703ccee995f27a80awrowe */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
a9a4544168a37b43bd180b3703ccee995f27a80awrowe /*
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * Parse IP addr manually, optionally allowing
a9a4544168a37b43bd180b3703ccee995f27a80awrowe * abbreviated net addresses like 192.168.
a9a4544168a37b43bd180b3703ccee995f27a80awrowe */
a9a4544168a37b43bd180b3703ccee995f27a80awrowe
a9a4544168a37b43bd180b3703ccee995f27a80awrowe /* Iterate over up to 4 (dotted) quads. */
4f9c22c4f27571d54197be9674e1fc0d528192aestriker for (quads = 0; quads < 4 && *addr != '\0'; ++quads) {
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar char *tmp;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar if (*addr == '/' && quads > 0) { /* netmask starts here. */
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar break;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
4f9c22c4f27571d54197be9674e1fc0d528192aestriker if (!apr_isdigit(*addr)) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe return 0; /* no digit at start of quad */
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe ip_addr[quads] = strtol(addr, &tmp, 0);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (tmp == addr) { /* expected a digit, found something else */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe return 0;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (ip_addr[quads] < 0 || ip_addr[quads] > 255) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe /* invalid octet */
cf6ef072483172309861d06e85b1aeff4573c060wrowe return 0;
cf6ef072483172309861d06e85b1aeff4573c060wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe addr = tmp;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (*addr == '.' && quads != 3) {
0e58e92812f2f679d6bf2ff66cbcfa6c1d1e14bbjerenkrantz ++addr; /* after the 4th quad, a dot would be illegal */
0e58e92812f2f679d6bf2ff66cbcfa6c1d1e14bbjerenkrantz }
0e58e92812f2f679d6bf2ff66cbcfa6c1d1e14bbjerenkrantz }
cf6ef072483172309861d06e85b1aeff4573c060wrowe
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe for (This->addr.s_addr = 0, i = 0; i < quads; ++i) {
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe This->addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe }
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (addr[0] == '/' && apr_isdigit(addr[1])) { /* net mask follows: */
4f9c22c4f27571d54197be9674e1fc0d528192aestriker char *tmp;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe ++addr;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe bits = strtol(addr, &tmp, 0);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (tmp == addr) { /* expected a digit, found something else */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe return 0;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe addr = tmp;
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe
4f9c22c4f27571d54197be9674e1fc0d528192aestriker if (bits < 0 || bits > 32) { /* netmask must be between 0 and 32 */
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe return 0;
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe }
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe }
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe else {
59513b1275fdc2021d4949ee03ae8229469abb86wrowe /*
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * Determine (i.e., "guess") netmask by counting the
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe * number of trailing .0's; reduce #quads appropriately
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * (so that 192.168.0.0 is equivalent to 192.168.)
4f9c22c4f27571d54197be9674e1fc0d528192aestriker */
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe while (quads > 0 && ip_addr[quads - 1] == 0) {
4f9c22c4f27571d54197be9674e1fc0d528192aestriker --quads;
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe }
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe
4f9c22c4f27571d54197be9674e1fc0d528192aestriker /* "IP Address should be given in dotted-quad form, optionally followed by a netmask (e.g., 192.168.111.0/24)"; */
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe if (quads < 1) {
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe return 0;
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe }
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe /* every zero-byte counts as 8 zero-bits */
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe bits = 8 * quads;
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe if (bits != 32) { /* no warning for fully qualified IP address */
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe "Warning: NetMask not supplied with IP-Addr; guessing: %s/%ld",
cf6ef072483172309861d06e85b1aeff4573c060wrowe inet_ntoa(This->addr), bits);
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe }
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe }
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe This->mask.s_addr = htonl(APR_INADDR_NONE << (32 - bits));
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
4f9c22c4f27571d54197be9674e1fc0d528192aestriker if (*addr == '\0' && (This->addr.s_addr & ~This->mask.s_addr) != 0) {
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe "Warning: NetMask and IP-Addr disagree in %s/%ld",
4f9c22c4f27571d54197be9674e1fc0d528192aestriker inet_ntoa(This->addr), bits);
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe This->addr.s_addr &= This->mask.s_addr;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe " Set to %s/%ld", inet_ntoa(This->addr), bits);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker }
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe if (*addr == '\0') {
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe This->matcher = proxy_match_ipaddr;
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe return 1;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker }
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe else {
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe return (*addr == '\0'); /* okay iff we've parsed the whole string */
4f9c22c4f27571d54197be9674e1fc0d528192aestriker }
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe}
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe/* Return TRUE if addr represents an IP address (or an IP network address) */
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowestatic int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r)
4f9c22c4f27571d54197be9674e1fc0d528192aestriker{
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe int i, ip_addr[4];
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe struct in_addr addr, *ip;
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe const char *host = proxy_get_host_of_request(r);
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe if (host == NULL) { /* oops! */
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe return 0;
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe }
cf6ef072483172309861d06e85b1aeff4573c060wrowe
4f9c22c4f27571d54197be9674e1fc0d528192aestriker memset(&addr, '\0', sizeof addr);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker memset(ip_addr, '\0', sizeof ip_addr);
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe if (4 == sscanf(host, "%d.%d.%d.%d", &ip_addr[0], &ip_addr[1], &ip_addr[2], &ip_addr[3])) {
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe for (addr.s_addr = 0, i = 0; i < 4; ++i) {
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe /* ap_proxy_is_ipaddr() already confirmed that we have
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe * a valid octet in ip_addr[i]
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe */
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe }
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe
38bcc87d9a06e8ba81165421403f275eca4e313btrawick if (This->addr.s_addr == (addr.s_addr & This->mask.s_addr)) {
38bcc87d9a06e8ba81165421403f275eca4e313btrawick#if DEBUGGING
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
0e58e92812f2f679d6bf2ff66cbcfa6c1d1e14bbjerenkrantz "1)IP-Match: %s[%s] <-> ", host, inet_ntoa(addr));
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe "%s/", inet_ntoa(This->addr));
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe "%s", inet_ntoa(This->mask));
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe#endif
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe return 1;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker }
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe#if DEBUGGING
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe else {
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe "1)IP-NoMatch: %s[%s] <-> ", host, inet_ntoa(addr));
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe "%s/", inet_ntoa(This->addr));
0e58e92812f2f679d6bf2ff66cbcfa6c1d1e14bbjerenkrantz ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe "%s", inet_ntoa(This->mask));
0e58e92812f2f679d6bf2ff66cbcfa6c1d1e14bbjerenkrantz }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe#endif
cf6ef072483172309861d06e85b1aeff4573c060wrowe }
cf6ef072483172309861d06e85b1aeff4573c060wrowe else {
8aefbd756763807188d2e3ce336a8680e4893066wrowe struct apr_sockaddr_t *reqaddr;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (apr_sockaddr_info_get(&reqaddr, host, APR_UNSPEC, 0, 0, r->pool)
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe != APR_SUCCESS) {
4f9c22c4f27571d54197be9674e1fc0d528192aestriker#if DEBUGGING
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe "2)IP-NoMatch: hostname=%s msg=Host not found", host);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe#endif
cf6ef072483172309861d06e85b1aeff4573c060wrowe return 0;
cf6ef072483172309861d06e85b1aeff4573c060wrowe }
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
4f9c22c4f27571d54197be9674e1fc0d528192aestriker /* Try to deal with multiple IP addr's for a host */
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz /* FIXME: This needs to be able to deal with IPv6 */
cf6ef072483172309861d06e85b1aeff4573c060wrowe while (reqaddr) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe ip = (struct in_addr *) reqaddr->ipaddr_ptr;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (This->addr.s_addr == (ip->s_addr & This->mask.s_addr)) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe#if DEBUGGING
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz "3)IP-Match: %s[%s] <-> ", host, inet_ntoa(*ip));
4f9c22c4f27571d54197be9674e1fc0d528192aestriker ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
548b2980e83f609186a76e98fb245d02e8547bc3jerenkrantz "%s/", inet_ntoa(This->addr));
548b2980e83f609186a76e98fb245d02e8547bc3jerenkrantz ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe "%s", inet_ntoa(This->mask));
548b2980e83f609186a76e98fb245d02e8547bc3jerenkrantz#endif
0e58e92812f2f679d6bf2ff66cbcfa6c1d1e14bbjerenkrantz return 1;
0e58e92812f2f679d6bf2ff66cbcfa6c1d1e14bbjerenkrantz }
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz#if DEBUGGING
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar else {
8aefbd756763807188d2e3ce336a8680e4893066wrowe ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe "3)IP-NoMatch: %s[%s] <-> ", host, inet_ntoa(*ip));
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe "%s/", inet_ntoa(This->addr));
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8aefbd756763807188d2e3ce336a8680e4893066wrowe "%s", inet_ntoa(This->mask));
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe#endif
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe reqaddr = reqaddr->next;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
4f9c22c4f27571d54197be9674e1fc0d528192aestriker }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe return 0;
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar}
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar/* Return TRUE if addr represents a domain name */
8aefbd756763807188d2e3ce336a8680e4893066wrowePROXY_DECLARE(int) ap_proxy_is_domainname(struct dirconn_entry *This, apr_pool_t *p)
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe{
4f9c22c4f27571d54197be9674e1fc0d528192aestriker char *addr = This->name;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe int i;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe /* Domain name must start with a '.' */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (addr[0] != '.') {
f08810eff40a2bddd2bc0103453c4ae775ea62bewrowe return 0;
f08810eff40a2bddd2bc0103453c4ae775ea62bewrowe }
f08810eff40a2bddd2bc0103453c4ae775ea62bewrowe
f08810eff40a2bddd2bc0103453c4ae775ea62bewrowe /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
f08810eff40a2bddd2bc0103453c4ae775ea62bewrowe for (i = 0; apr_isalnum(addr[i]) || addr[i] == '-' || addr[i] == '.'; ++i) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe continue;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe#if 0
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (addr[i] == ':') {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe "@@@@ handle optional port in proxy_is_domainname()");
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe /* @@@@ handle optional port */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe#endif
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (addr[i] != '\0') {
4f9c22c4f27571d54197be9674e1fc0d528192aestriker return 0;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe /* Strip trailing dots */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe for (i = strlen(addr) - 1; i > 0 && addr[i] == '.'; --i) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe addr[i] = '\0';
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar This->matcher = proxy_match_domainname;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker return 1;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe}
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar/* Return TRUE if host "host" is in domain "domain" */
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoarstatic int proxy_match_domainname(struct dirconn_entry *This, request_rec *r)
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe{
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar const char *host = proxy_get_host_of_request(r);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe int d_len = strlen(This->name), h_len;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (host == NULL) { /* some error was logged already */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe return 0;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe h_len = strlen(host);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz /* @@@ do this within the setup? */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe /* Ignore trailing dots in domain comparison: */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe while (d_len > 0 && This->name[d_len - 1] == '.') {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe --d_len;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe while (h_len > 0 && host[h_len - 1] == '.') {
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar --h_len;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar return h_len > d_len
8aefbd756763807188d2e3ce336a8680e4893066wrowe && strncasecmp(&host[h_len - d_len], This->name, d_len) == 0;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe}
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz/* Return TRUE if host represents a host name */
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantzPROXY_DECLARE(int) ap_proxy_is_hostname(struct dirconn_entry *This, apr_pool_t *p)
4f9c22c4f27571d54197be9674e1fc0d528192aestriker{
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz struct apr_sockaddr_t *addr;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe char *host = This->name;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe int i;
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz /* Host names must not start with a '.' */
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz if (host[0] == '.') {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe return 0;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe for (i = 0; apr_isalnum(host[i]) || host[i] == '-' || host[i] == '.'; ++i);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (host[i] != '\0' || apr_sockaddr_info_get(&addr, host, APR_UNSPEC, 0, 0, p) != APR_SUCCESS) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe return 0;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe This->hostaddr = addr;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe /* Strip trailing dots */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe for (i = strlen(host) - 1; i > 0 && host[i] == '.'; --i) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe host[i] = '\0';
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar This->matcher = proxy_match_hostname;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe return 1;
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar}
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe/* Return TRUE if host "host" is equal to host2 "host2" */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowestatic int proxy_match_hostname(struct dirconn_entry *This, request_rec *r)
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe{
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe char *host = This->name;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker const char *host2 = proxy_get_host_of_request(r);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe int h2_len;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe int h1_len;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (host == NULL || host2 == NULL) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe return 0; /* oops! */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe h2_len = strlen(host2);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe h1_len = strlen(host);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe#if 0
4f9c22c4f27571d54197be9674e1fc0d528192aestriker struct apr_sockaddr_t *addr = *This->hostaddr;
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe /* Try to deal with multiple IP addr's for a host */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe while (addr) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (addr->ipaddr_ptr == ? ? ? ? ? ? ? ? ? ? ? ? ?)
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe return 1;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe addr = addr->next;
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar }
4f9c22c4f27571d54197be9674e1fc0d528192aestriker#endif
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe /* Ignore trailing dots in host2 comparison: */
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar while (h2_len > 0 && host2[h2_len - 1] == '.') {
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar --h2_len;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar while (h1_len > 0 && host[h1_len - 1] == '.') {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe --h1_len;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe return h1_len == h2_len
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe && strncasecmp(host, host2, h1_len) == 0;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe}
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz/* Return TRUE if addr is to be matched as a word */
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantzPROXY_DECLARE(int) ap_proxy_is_word(struct dirconn_entry *This, apr_pool_t *p)
4f9c22c4f27571d54197be9674e1fc0d528192aestriker{
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz This->matcher = proxy_match_word;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe return 1;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe}
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
c2cf53a40a9814eb91db2cdf820f97d943f21628coar/* Return TRUE if string "str2" occurs literally in "str1" */
c2cf53a40a9814eb91db2cdf820f97d943f21628coarstatic int proxy_match_word(struct dirconn_entry *This, request_rec *r)
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe{
c2cf53a40a9814eb91db2cdf820f97d943f21628coar const char *host = proxy_get_host_of_request(r);
2787ef5edc27fa4f6777ba8d51aa48fd9fdf54bbwrowe return host != NULL && ap_strstr_c(host, This->name) != NULL;
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz}
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz/* checks whether a host in uri_addr matches proxyblock */
4f9c22c4f27571d54197be9674e1fc0d528192aestrikerPROXY_DECLARE(int) ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf,
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz apr_sockaddr_t *uri_addr)
2787ef5edc27fa4f6777ba8d51aa48fd9fdf54bbwrowe{
2787ef5edc27fa4f6777ba8d51aa48fd9fdf54bbwrowe int j;
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz apr_sockaddr_t * src_uri_addr = uri_addr;
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz /* XXX FIXME: conf->noproxies->elts is part of an opaque structure */
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz for (j = 0; j < conf->noproxies->nelts; j++) {
2787ef5edc27fa4f6777ba8d51aa48fd9fdf54bbwrowe struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker struct apr_sockaddr_t *conf_addr = npent[j].addr;
2787ef5edc27fa4f6777ba8d51aa48fd9fdf54bbwrowe uri_addr = src_uri_addr;
2787ef5edc27fa4f6777ba8d51aa48fd9fdf54bbwrowe ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, r->server,
2787ef5edc27fa4f6777ba8d51aa48fd9fdf54bbwrowe "proxy: checking remote machine [%s] against [%s]", uri_addr->hostname, npent[j].name);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if ((npent[j].name && ap_strstr_c(uri_addr->hostname, npent[j].name))
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe || npent[j].name[0] == '*') {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe "proxy: connect to remote machine %s blocked: name %s matched", uri_addr->hostname, npent[j].name);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe return HTTP_FORBIDDEN;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
2520f59894a3e07fefa881ef68aaded763a8d447ben while (conf_addr) {
0e58e92812f2f679d6bf2ff66cbcfa6c1d1e14bbjerenkrantz uri_addr = src_uri_addr;
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar while (uri_addr) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe char *conf_ip;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe char *uri_ip;
8aefbd756763807188d2e3ce336a8680e4893066wrowe apr_sockaddr_ip_get(&conf_ip, conf_addr);
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar apr_sockaddr_ip_get(&uri_ip, uri_addr);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, r->server,
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar "proxy: ProxyBlock comparing %s and %s", conf_ip, uri_ip);
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (!apr_strnatcasecmp(conf_ip, uri_ip)) {
4f9c22c4f27571d54197be9674e1fc0d528192aestriker ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe "proxy: connect to remote machine %s blocked: IP %s matched", uri_addr->hostname, conf_ip);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe return HTTP_FORBIDDEN;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
4f9c22c4f27571d54197be9674e1fc0d528192aestriker uri_addr = uri_addr->next;
0e58e92812f2f679d6bf2ff66cbcfa6c1d1e14bbjerenkrantz }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe conf_addr = conf_addr->next;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
0e58e92812f2f679d6bf2ff66cbcfa6c1d1e14bbjerenkrantz }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe return OK;
0e58e92812f2f679d6bf2ff66cbcfa6c1d1e14bbjerenkrantz}
0e58e92812f2f679d6bf2ff66cbcfa6c1d1e14bbjerenkrantz
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe/* set up the minimal filter set */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowePROXY_DECLARE(int) ap_proxy_pre_http_request(conn_rec *c, request_rec *r)
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe{
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe ap_add_input_filter("HTTP_IN", NULL, r, c);
0e58e92812f2f679d6bf2ff66cbcfa6c1d1e14bbjerenkrantz return OK;
0e58e92812f2f679d6bf2ff66cbcfa6c1d1e14bbjerenkrantz}
0e58e92812f2f679d6bf2ff66cbcfa6c1d1e14bbjerenkrantz
0e58e92812f2f679d6bf2ff66cbcfa6c1d1e14bbjerenkrantz/*
8aefbd756763807188d2e3ce336a8680e4893066wrowe * converts a series of buckets into a string
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * XXX: BillS says this function performs essentially the same function as
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe * ap_rgetline() in protocol.c. Deprecate this function and use ap_rgetline()
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * instead? I think ap_proxy_string_read() will not work properly on non ASCII
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe * (EBCDIC) machines either.
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe */
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoarPROXY_DECLARE(apr_status_t) ap_proxy_string_read(conn_rec *c, apr_bucket_brigade *bb,
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe char *buff, apr_size_t bufflen, int *eos)
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar{
8aefbd756763807188d2e3ce336a8680e4893066wrowe apr_bucket *e;
cf6ef072483172309861d06e85b1aeff4573c060wrowe apr_status_t rv;
cf6ef072483172309861d06e85b1aeff4573c060wrowe char *pos = buff;
cf6ef072483172309861d06e85b1aeff4573c060wrowe char *response;
cf6ef072483172309861d06e85b1aeff4573c060wrowe int found = 0;
cf6ef072483172309861d06e85b1aeff4573c060wrowe apr_size_t len;
cf6ef072483172309861d06e85b1aeff4573c060wrowe
cf6ef072483172309861d06e85b1aeff4573c060wrowe /* start with an empty string */
4f9c22c4f27571d54197be9674e1fc0d528192aestriker buff[0] = 0;
cf6ef072483172309861d06e85b1aeff4573c060wrowe *eos = 0;
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe
cf6ef072483172309861d06e85b1aeff4573c060wrowe /* loop through each brigade */
4f9c22c4f27571d54197be9674e1fc0d528192aestriker while (!found) {
69adb3d949e3dd17c0492a01fc2cf298832c7eefwrowe /* get brigade from network one line at a time */
69adb3d949e3dd17c0492a01fc2cf298832c7eefwrowe if (APR_SUCCESS != (rv = ap_get_brigade(c->input_filters, bb,
cf6ef072483172309861d06e85b1aeff4573c060wrowe AP_MODE_GETLINE,
cf6ef072483172309861d06e85b1aeff4573c060wrowe APR_BLOCK_READ,
cf6ef072483172309861d06e85b1aeff4573c060wrowe 0))) {
cf6ef072483172309861d06e85b1aeff4573c060wrowe return rv;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe /* loop through each bucket */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe while (!found) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (*eos || APR_BRIGADE_EMPTY(bb)) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe /* The connection aborted or timed out */
cf6ef072483172309861d06e85b1aeff4573c060wrowe return APR_ECONNABORTED;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
cf6ef072483172309861d06e85b1aeff4573c060wrowe e = APR_BRIGADE_FIRST(bb);
c2cf53a40a9814eb91db2cdf820f97d943f21628coar if (APR_BUCKET_IS_EOS(e)) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe *eos = 1;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
c2cf53a40a9814eb91db2cdf820f97d943f21628coar else {
c2cf53a40a9814eb91db2cdf820f97d943f21628coar if (APR_SUCCESS != (rv = apr_bucket_read(e,
8aefbd756763807188d2e3ce336a8680e4893066wrowe (const char **)&response,
cf6ef072483172309861d06e85b1aeff4573c060wrowe &len,
8aefbd756763807188d2e3ce336a8680e4893066wrowe APR_BLOCK_READ))) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe return rv;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe /*
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe * is string LF terminated?
8aefbd756763807188d2e3ce336a8680e4893066wrowe * XXX: This check can be made more efficient by simply checking
8aefbd756763807188d2e3ce336a8680e4893066wrowe * if the last character in the 'response' buffer is an ASCII_LF.
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * See ap_rgetline() for an example.
cf6ef072483172309861d06e85b1aeff4573c060wrowe */
4f9c22c4f27571d54197be9674e1fc0d528192aestriker if (memchr(response, APR_ASCII_LF, len)) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe found = 1;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe /* concat strings until buff is full - then throw the data away */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (len > ((bufflen-1)-(pos-buff))) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe len = (bufflen-1)-(pos-buff);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
69adb3d949e3dd17c0492a01fc2cf298832c7eefwrowe if (len > 0) {
69adb3d949e3dd17c0492a01fc2cf298832c7eefwrowe memcpy(pos, response, len);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe pos += len;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe APR_BUCKET_REMOVE(e);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe apr_bucket_destroy(e);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
4f9c22c4f27571d54197be9674e1fc0d528192aestriker *pos = '\0';
cf6ef072483172309861d06e85b1aeff4573c060wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
cadddb2c31d24d48f4017db4df0a29687432326cwrowe return APR_SUCCESS;
cadddb2c31d24d48f4017db4df0a29687432326cwrowe}
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
cf6ef072483172309861d06e85b1aeff4573c060wrowe/* unmerge an element in the table */
0e58e92812f2f679d6bf2ff66cbcfa6c1d1e14bbjerenkrantzPROXY_DECLARE(void) ap_proxy_table_unmerge(apr_pool_t *p, apr_table_t *t, char *key)
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe{
8aefbd756763807188d2e3ce336a8680e4893066wrowe apr_off_t offset = 0;
cf6ef072483172309861d06e85b1aeff4573c060wrowe apr_off_t count = 0;
cf6ef072483172309861d06e85b1aeff4573c060wrowe char *value = NULL;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
4f9c22c4f27571d54197be9674e1fc0d528192aestriker /* get the value to unmerge */
cf6ef072483172309861d06e85b1aeff4573c060wrowe const char *initial = apr_table_get(t, key);
2d399cd7535887fceaa9f8f116eb98ce68ddd602trawick if (!initial) {
c2cf53a40a9814eb91db2cdf820f97d943f21628coar return;
c2cf53a40a9814eb91db2cdf820f97d943f21628coar }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe value = apr_pstrdup(p, initial);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* remove the value from the headers */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe apr_table_unset(t, key);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
cf6ef072483172309861d06e85b1aeff4573c060wrowe /* find each comma */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe while (value[count]) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (value[count] == ',') {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe value[count] = 0;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe apr_table_add(t, key, value + offset);
cf6ef072483172309861d06e85b1aeff4573c060wrowe offset = count + 1;
2d399cd7535887fceaa9f8f116eb98ce68ddd602trawick }
4f9c22c4f27571d54197be9674e1fc0d528192aestriker count++;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker }
4f9c22c4f27571d54197be9674e1fc0d528192aestriker apr_table_add(t, key, value + offset);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe}
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowePROXY_DECLARE(const char *) ap_proxy_location_reverse_map(request_rec *r,
8aefbd756763807188d2e3ce336a8680e4893066wrowe proxy_dir_conf *conf, const char *url)
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe{
cf6ef072483172309861d06e85b1aeff4573c060wrowe proxy_req_conf *rconf;
cf6ef072483172309861d06e85b1aeff4573c060wrowe struct proxy_alias *ent;
cf6ef072483172309861d06e85b1aeff4573c060wrowe int i, l1, l2;
cf6ef072483172309861d06e85b1aeff4573c060wrowe char *u;
cf6ef072483172309861d06e85b1aeff4573c060wrowe
69adb3d949e3dd17c0492a01fc2cf298832c7eefwrowe /*
cf6ef072483172309861d06e85b1aeff4573c060wrowe * XXX FIXME: Make sure this handled the ambiguous case of the :<PORT>
cf6ef072483172309861d06e85b1aeff4573c060wrowe * after the hostname
cf6ef072483172309861d06e85b1aeff4573c060wrowe * XXX FIXME: Ensure the /uri component is a case sensitive match
cf6ef072483172309861d06e85b1aeff4573c060wrowe */
cf6ef072483172309861d06e85b1aeff4573c060wrowe if (r->proxyreq != PROXYREQ_REVERSE) {
cf6ef072483172309861d06e85b1aeff4573c060wrowe return url;
cf6ef072483172309861d06e85b1aeff4573c060wrowe }
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
cf6ef072483172309861d06e85b1aeff4573c060wrowe l1 = strlen(url);
cf6ef072483172309861d06e85b1aeff4573c060wrowe if (conf->interpolate_env == 1) {
cf6ef072483172309861d06e85b1aeff4573c060wrowe rconf = ap_get_module_config(r->request_config, &proxy_module);
cf6ef072483172309861d06e85b1aeff4573c060wrowe ent = (struct proxy_alias *)rconf->raliases->elts;
cf6ef072483172309861d06e85b1aeff4573c060wrowe }
cf6ef072483172309861d06e85b1aeff4573c060wrowe else {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe ent = (struct proxy_alias *)conf->raliases->elts;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe for (i = 0; i < conf->raliases->nelts; i++) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe proxy_server_conf *sconf = (proxy_server_conf *)
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe ap_get_module_config(r->server->module_config, &proxy_module);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe proxy_balancer *balancer;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe const char *real = ent[i].real;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker /*
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe * First check if mapping against a balancer and see
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe * if we have such a entity. If so, then we need to
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar * find the particulars of the actual worker which may
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe * or may not be the right one... basically, we need
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar * to find which member actually handled this request.
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe */
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar if ((strncasecmp(real, "balancer://", 11) == 0) &&
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe (balancer = ap_proxy_get_balancer(r->pool, sconf, real))) {
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar int n, l3 = 0;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe proxy_worker **worker = (proxy_worker **)balancer->workers->elts;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe const char *urlpart = ap_strchr_c(real + 11, '/');
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (urlpart) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (!urlpart[1])
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe urlpart = NULL;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe else
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe l3 = strlen(urlpart);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe /* The balancer comparison is a bit trickier. Given the context
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe * BalancerMember balancer://alias http://example.com/foo
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * ProxyPassReverse /bash balancer://alias/bar
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe * translate url http://example.com/foo/bar/that to /bash/that
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe for (n = 0; n < balancer->workers->nelts; n++) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe l2 = strlen((*worker)->name);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (urlpart) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe /* urlpart (l3) assuredly starts with its own '/' */
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if ((*worker)->name[l2 - 1] == '/')
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar --l2;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker if (l1 >= l2 + l3
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe && strncasecmp((*worker)->name, url, l2) == 0
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe && strncmp(urlpart, url + l2, l3) == 0) {
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar u = apr_pstrcat(r->pool, ent[i].fake, &url[l2 + l3],
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar NULL);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe return ap_construct_url(r->pool, u, r);
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe else if (l1 >= l2 && strncasecmp((*worker)->name, url, l2) == 0) {
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe u = apr_pstrcat(r->pool, ent[i].fake, &url[l2], NULL);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe return ap_construct_url(r->pool, u, r);
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe worker++;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe }
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe else {
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar const char *part = url;
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe l2 = strlen(real);
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar if (real[0] == '/') {
8aefbd756763807188d2e3ce336a8680e4893066wrowe part = ap_strstr_c(url, "://");
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (part) {
c2cf53a40a9814eb91db2cdf820f97d943f21628coar part = ap_strchr_c(part+3, '/');
c2cf53a40a9814eb91db2cdf820f97d943f21628coar if (part) {
c2cf53a40a9814eb91db2cdf820f97d943f21628coar l1 = strlen(part);
c2cf53a40a9814eb91db2cdf820f97d943f21628coar }
c2cf53a40a9814eb91db2cdf820f97d943f21628coar else {
8aefbd756763807188d2e3ce336a8680e4893066wrowe part = url;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe else {
8aefbd756763807188d2e3ce336a8680e4893066wrowe part = url;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (l1 >= l2 && strncasecmp(real, part, l2) == 0) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe u = apr_pstrcat(r->pool, ent[i].fake, &part[l2], NULL);
8aefbd756763807188d2e3ce336a8680e4893066wrowe return ap_construct_url(r->pool, u, r);
c2cf53a40a9814eb91db2cdf820f97d943f21628coar }
c2cf53a40a9814eb91db2cdf820f97d943f21628coar }
2d399cd7535887fceaa9f8f116eb98ce68ddd602trawick }
c2cf53a40a9814eb91db2cdf820f97d943f21628coar
8aefbd756763807188d2e3ce336a8680e4893066wrowe return url;
8aefbd756763807188d2e3ce336a8680e4893066wrowe}
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe/*
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe * Cookies are a bit trickier to match: we've got two substrings to worry
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe * about, and we can't just find them with strstr 'cos of case. Regexp
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe * matching would be an easy fix, but for better consistency with all the
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe * other matches we'll refrain and use apr_strmatch to find path=/domain=
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe * and stick to plain strings for the config values.
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe */
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoarPROXY_DECLARE(const char *) ap_proxy_cookie_reverse_map(request_rec *r,
0540a0b469147b52e858587270dba31c2aaa9e09wrowe proxy_dir_conf *conf, const char *str)
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar{
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar proxy_req_conf *rconf = ap_get_module_config(r->request_config,
0540a0b469147b52e858587270dba31c2aaa9e09wrowe &proxy_module);
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar struct proxy_alias *ent;
0540a0b469147b52e858587270dba31c2aaa9e09wrowe size_t len = strlen(str);
0540a0b469147b52e858587270dba31c2aaa9e09wrowe const char *newpath = NULL;
a9a4544168a37b43bd180b3703ccee995f27a80awrowe const char *newdomain = NULL;
0540a0b469147b52e858587270dba31c2aaa9e09wrowe const char *pathp;
0540a0b469147b52e858587270dba31c2aaa9e09wrowe const char *domainp;
0540a0b469147b52e858587270dba31c2aaa9e09wrowe const char *pathe = NULL;
dc8692c6c0ca616a09aa12dad005f2ef23baa1a0wrowe const char *domaine = NULL;
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar size_t l1, l2, poffs = 0, doffs = 0;
0540a0b469147b52e858587270dba31c2aaa9e09wrowe int i;
0540a0b469147b52e858587270dba31c2aaa9e09wrowe int ddiff = 0;
0540a0b469147b52e858587270dba31c2aaa9e09wrowe int pdiff = 0;
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar char *ret;
0540a0b469147b52e858587270dba31c2aaa9e09wrowe
dc8692c6c0ca616a09aa12dad005f2ef23baa1a0wrowe if (r->proxyreq != PROXYREQ_REVERSE) {
0540a0b469147b52e858587270dba31c2aaa9e09wrowe return str;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
0540a0b469147b52e858587270dba31c2aaa9e09wrowe /*
a2a0abd88b19e042a3eb2a9fa1702c25ad51303dwrowe * Find the match and replacement, but save replacing until we've done
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * both path and domain so we know the new strlen
948096a99010fccf648814fecf38f75c689172d7wrowe */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if ((pathp = apr_strmatch(conf->cookie_path_str, str, len)) != NULL) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb pathp += 5;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker poffs = pathp - str;
0540a0b469147b52e858587270dba31c2aaa9e09wrowe pathe = ap_strchr_c(pathp, ';');
948096a99010fccf648814fecf38f75c689172d7wrowe l1 = pathe ? (pathe - pathp) : strlen(pathp);
948096a99010fccf648814fecf38f75c689172d7wrowe pathe = pathp + l1 ;
948096a99010fccf648814fecf38f75c689172d7wrowe if (conf->interpolate_env == 1) {
948096a99010fccf648814fecf38f75c689172d7wrowe ent = (struct proxy_alias *)rconf->cookie_paths->elts;
dc8692c6c0ca616a09aa12dad005f2ef23baa1a0wrowe }
dc8692c6c0ca616a09aa12dad005f2ef23baa1a0wrowe else {
053497224246c4dbef9af594cacf5c00ed271e6cwrowe ent = (struct proxy_alias *)conf->cookie_paths->elts;
0540a0b469147b52e858587270dba31c2aaa9e09wrowe }
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz for (i = 0; i < conf->cookie_paths->nelts; i++) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb l2 = strlen(ent[i].fake);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (l1 >= l2 && strncmp(ent[i].fake, pathp, l2) == 0) {
42da244268b11ec661b528510f80a18b73c51727brianp newpath = ent[i].real;
42da244268b11ec661b528510f80a18b73c51727brianp pdiff = strlen(newpath) - l1;
948096a99010fccf648814fecf38f75c689172d7wrowe break;
948096a99010fccf648814fecf38f75c689172d7wrowe }
948096a99010fccf648814fecf38f75c689172d7wrowe }
948096a99010fccf648814fecf38f75c689172d7wrowe }
948096a99010fccf648814fecf38f75c689172d7wrowe
948096a99010fccf648814fecf38f75c689172d7wrowe if ((domainp = apr_strmatch(conf->cookie_domain_str, str, len)) != NULL) {
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz domainp += 7;
948096a99010fccf648814fecf38f75c689172d7wrowe doffs = domainp - str;
948096a99010fccf648814fecf38f75c689172d7wrowe domaine = ap_strchr_c(domainp, ';');
948096a99010fccf648814fecf38f75c689172d7wrowe l1 = domaine ? (domaine - domainp) : strlen(domainp);
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz domaine = domainp + l1;
948096a99010fccf648814fecf38f75c689172d7wrowe if (conf->interpolate_env == 1) {
948096a99010fccf648814fecf38f75c689172d7wrowe ent = (struct proxy_alias *)rconf->cookie_domains->elts;
053497224246c4dbef9af594cacf5c00ed271e6cwrowe }
948096a99010fccf648814fecf38f75c689172d7wrowe else {
948096a99010fccf648814fecf38f75c689172d7wrowe ent = (struct proxy_alias *)conf->cookie_domains->elts;
948096a99010fccf648814fecf38f75c689172d7wrowe }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb for (i = 0; i < conf->cookie_domains->nelts; i++) {
c2cf53a40a9814eb91db2cdf820f97d943f21628coar l2 = strlen(ent[i].fake);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker if (l1 >= l2 && strncasecmp(ent[i].fake, domainp, l2) == 0) {
c2cf53a40a9814eb91db2cdf820f97d943f21628coar newdomain = ent[i].real;
948096a99010fccf648814fecf38f75c689172d7wrowe ddiff = strlen(newdomain) - l1;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker break;
948096a99010fccf648814fecf38f75c689172d7wrowe }
948096a99010fccf648814fecf38f75c689172d7wrowe }
053497224246c4dbef9af594cacf5c00ed271e6cwrowe }
a9a4544168a37b43bd180b3703ccee995f27a80awrowe
948096a99010fccf648814fecf38f75c689172d7wrowe if (newpath) {
a9a4544168a37b43bd180b3703ccee995f27a80awrowe ret = apr_palloc(r->pool, len + pdiff + ddiff + 1);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker l1 = strlen(newpath);
a9a4544168a37b43bd180b3703ccee995f27a80awrowe if (newdomain) {
a9a4544168a37b43bd180b3703ccee995f27a80awrowe l2 = strlen(newdomain);
a9a4544168a37b43bd180b3703ccee995f27a80awrowe if (doffs > poffs) {
a9a4544168a37b43bd180b3703ccee995f27a80awrowe memcpy(ret, str, poffs);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker memcpy(ret + poffs, newpath, l1);
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar memcpy(ret + poffs + l1, pathe, domainp - pathe);
948096a99010fccf648814fecf38f75c689172d7wrowe memcpy(ret + doffs + pdiff, newdomain, l2);
948096a99010fccf648814fecf38f75c689172d7wrowe strcpy(ret + doffs + pdiff + l2, domaine);
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar }
948096a99010fccf648814fecf38f75c689172d7wrowe else {
948096a99010fccf648814fecf38f75c689172d7wrowe memcpy(ret, str, doffs) ;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker memcpy(ret + doffs, newdomain, l2);
948096a99010fccf648814fecf38f75c689172d7wrowe memcpy(ret + doffs + l2, domaine, pathp - domaine);
948096a99010fccf648814fecf38f75c689172d7wrowe memcpy(ret + poffs + ddiff, newpath, l1);
0540a0b469147b52e858587270dba31c2aaa9e09wrowe strcpy(ret + poffs + ddiff + l1, pathe);
948096a99010fccf648814fecf38f75c689172d7wrowe }
aa047239dedf0d26e8efecfade32e7337f35df19wrowe }
948096a99010fccf648814fecf38f75c689172d7wrowe else {
948096a99010fccf648814fecf38f75c689172d7wrowe memcpy(ret, str, poffs);
948096a99010fccf648814fecf38f75c689172d7wrowe memcpy(ret + poffs, newpath, l1);
948096a99010fccf648814fecf38f75c689172d7wrowe strcpy(ret + poffs + l1, pathe);
948096a99010fccf648814fecf38f75c689172d7wrowe }
053497224246c4dbef9af594cacf5c00ed271e6cwrowe }
0540a0b469147b52e858587270dba31c2aaa9e09wrowe else {
053497224246c4dbef9af594cacf5c00ed271e6cwrowe if (newdomain) {
4f9c22c4f27571d54197be9674e1fc0d528192aestriker ret = apr_palloc(r->pool, len + pdiff + ddiff + 1);
0540a0b469147b52e858587270dba31c2aaa9e09wrowe l2 = strlen(newdomain);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker memcpy(ret, str, doffs);
aa047239dedf0d26e8efecfade32e7337f35df19wrowe memcpy(ret + doffs, newdomain, l2);
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz strcpy(ret + doffs+l2, domaine);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
053497224246c4dbef9af594cacf5c00ed271e6cwrowe else {
4f9c22c4f27571d54197be9674e1fc0d528192aestriker ret = (char *)str; /* no change */
053497224246c4dbef9af594cacf5c00ed271e6cwrowe }
053497224246c4dbef9af594cacf5c00ed271e6cwrowe }
053497224246c4dbef9af594cacf5c00ed271e6cwrowe
4f9c22c4f27571d54197be9674e1fc0d528192aestriker return ret;
c2cf53a40a9814eb91db2cdf820f97d943f21628coar}
c2cf53a40a9814eb91db2cdf820f97d943f21628coar
c2cf53a40a9814eb91db2cdf820f97d943f21628coarPROXY_DECLARE(proxy_balancer *) ap_proxy_get_balancer(apr_pool_t *p,
c2cf53a40a9814eb91db2cdf820f97d943f21628coar proxy_server_conf *conf,
4f9c22c4f27571d54197be9674e1fc0d528192aestriker const char *url)
4f9c22c4f27571d54197be9674e1fc0d528192aestriker{
4f9c22c4f27571d54197be9674e1fc0d528192aestriker proxy_balancer *balancer;
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz char *c, *uri = apr_pstrdup(p, url);
053497224246c4dbef9af594cacf5c00ed271e6cwrowe int i;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
948096a99010fccf648814fecf38f75c689172d7wrowe c = strchr(uri, ':');
948096a99010fccf648814fecf38f75c689172d7wrowe if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0') {
948096a99010fccf648814fecf38f75c689172d7wrowe return NULL;
0540a0b469147b52e858587270dba31c2aaa9e09wrowe }
948096a99010fccf648814fecf38f75c689172d7wrowe /* remove path from uri */
948096a99010fccf648814fecf38f75c689172d7wrowe if ((c = strchr(c + 3, '/'))) {
948096a99010fccf648814fecf38f75c689172d7wrowe *c = '\0';
948096a99010fccf648814fecf38f75c689172d7wrowe }
948096a99010fccf648814fecf38f75c689172d7wrowe balancer = (proxy_balancer *)conf->balancers->elts;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker for (i = 0; i < conf->balancers->nelts; i++) {
948096a99010fccf648814fecf38f75c689172d7wrowe if (strcasecmp(balancer->name, uri) == 0) {
948096a99010fccf648814fecf38f75c689172d7wrowe return balancer;
948096a99010fccf648814fecf38f75c689172d7wrowe }
948096a99010fccf648814fecf38f75c689172d7wrowe balancer++;
948096a99010fccf648814fecf38f75c689172d7wrowe }
948096a99010fccf648814fecf38f75c689172d7wrowe return NULL;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar
4f9c22c4f27571d54197be9674e1fc0d528192aestrikerPROXY_DECLARE(const char *) ap_proxy_add_balancer(proxy_balancer **balancer,
948096a99010fccf648814fecf38f75c689172d7wrowe apr_pool_t *p,
0540a0b469147b52e858587270dba31c2aaa9e09wrowe proxy_server_conf *conf,
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar const char *url)
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar{
0540a0b469147b52e858587270dba31c2aaa9e09wrowe char *c, *q, *uri = apr_pstrdup(p, url);
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar proxy_balancer_method *lbmethod;
696218c49632c863d18b25fa52ab63617088cb38wrowe
948096a99010fccf648814fecf38f75c689172d7wrowe c = strchr(uri, ':');
0540a0b469147b52e858587270dba31c2aaa9e09wrowe if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')
948096a99010fccf648814fecf38f75c689172d7wrowe return "Bad syntax for a balancer name";
948096a99010fccf648814fecf38f75c689172d7wrowe /* remove path from uri */
4f9c22c4f27571d54197be9674e1fc0d528192aestriker if ((q = strchr(c + 3, '/')))
948096a99010fccf648814fecf38f75c689172d7wrowe *q = '\0';
948096a99010fccf648814fecf38f75c689172d7wrowe
053497224246c4dbef9af594cacf5c00ed271e6cwrowe ap_str_tolower(uri);
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar *balancer = apr_array_push(conf->balancers);
948096a99010fccf648814fecf38f75c689172d7wrowe memset(*balancer, 0, sizeof(proxy_balancer));
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar
053497224246c4dbef9af594cacf5c00ed271e6cwrowe /*
053497224246c4dbef9af594cacf5c00ed271e6cwrowe * NOTE: The default method is byrequests, which we assume
a9a4544168a37b43bd180b3703ccee995f27a80awrowe * exists!
a9a4544168a37b43bd180b3703ccee995f27a80awrowe */
a9a4544168a37b43bd180b3703ccee995f27a80awrowe lbmethod = ap_lookup_provider(PROXY_LBMETHOD, "byrequests", "0");
948096a99010fccf648814fecf38f75c689172d7wrowe if (!lbmethod) {
948096a99010fccf648814fecf38f75c689172d7wrowe return "Can't find 'byrequests' lb method";
053497224246c4dbef9af594cacf5c00ed271e6cwrowe }
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar
053497224246c4dbef9af594cacf5c00ed271e6cwrowe (*balancer)->name = uri;
053497224246c4dbef9af594cacf5c00ed271e6cwrowe (*balancer)->lbmethod = lbmethod;
948096a99010fccf648814fecf38f75c689172d7wrowe (*balancer)->workers = apr_array_make(p, 5, sizeof(proxy_worker *));
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar /* XXX Is this a right place to create mutex */
948096a99010fccf648814fecf38f75c689172d7wrowe#if APR_HAS_THREADS
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (apr_thread_mutex_create(&((*balancer)->mutex),
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb APR_THREAD_MUTEX_DEFAULT, p) != APR_SUCCESS) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* XXX: Do we need to log something here */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return "can not create thread mutex";
a2a0abd88b19e042a3eb2a9fa1702c25ad51303dwrowe }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#endif
aa047239dedf0d26e8efecfade32e7337f35df19wrowe
aa047239dedf0d26e8efecfade32e7337f35df19wrowe return NULL;
aa047239dedf0d26e8efecfade32e7337f35df19wrowe}
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
0540a0b469147b52e858587270dba31c2aaa9e09wrowePROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
aa047239dedf0d26e8efecfade32e7337f35df19wrowe proxy_server_conf *conf,
aa047239dedf0d26e8efecfade32e7337f35df19wrowe const char *url)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
dc8692c6c0ca616a09aa12dad005f2ef23baa1a0wrowe proxy_worker *worker;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker proxy_worker *max_worker = NULL;
dc8692c6c0ca616a09aa12dad005f2ef23baa1a0wrowe int max_match = 0;
dc8692c6c0ca616a09aa12dad005f2ef23baa1a0wrowe int url_length;
b5bd19d82874782007a2f9bcb19341a483c1270cwrowe int min_match;
dc8692c6c0ca616a09aa12dad005f2ef23baa1a0wrowe int worker_name_length;
dc8692c6c0ca616a09aa12dad005f2ef23baa1a0wrowe const char *c;
dc8692c6c0ca616a09aa12dad005f2ef23baa1a0wrowe char *url_copy;
a2b181763cb35fd899feb4a436aeadaa80bf91eabrianp int i;
aa047239dedf0d26e8efecfade32e7337f35df19wrowe
aa047239dedf0d26e8efecfade32e7337f35df19wrowe c = ap_strchr_c(url, ':');
aa047239dedf0d26e8efecfade32e7337f35df19wrowe if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0') {
aa047239dedf0d26e8efecfade32e7337f35df19wrowe return NULL;
aa047239dedf0d26e8efecfade32e7337f35df19wrowe }
0540a0b469147b52e858587270dba31c2aaa9e09wrowe
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz url_copy = apr_pstrdup(p, url);
aa047239dedf0d26e8efecfade32e7337f35df19wrowe url_length = strlen(url);
aa047239dedf0d26e8efecfade32e7337f35df19wrowe
4f9c22c4f27571d54197be9674e1fc0d528192aestriker /*
aa047239dedf0d26e8efecfade32e7337f35df19wrowe * We need to find the start of the path and
aa047239dedf0d26e8efecfade32e7337f35df19wrowe * therefore we know the length of the scheme://hostname/
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * part to we can force-lowercase everything up to
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * the start of the path.
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb c = ap_strchr_c(c+3, '/');
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (c) {
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz char *pathstart;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb pathstart = url_copy + (c - url);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb *pathstart = '\0';
aa047239dedf0d26e8efecfade32e7337f35df19wrowe ap_str_tolower(url_copy);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker min_match = strlen(url_copy);
aa047239dedf0d26e8efecfade32e7337f35df19wrowe *pathstart = '/';
aa047239dedf0d26e8efecfade32e7337f35df19wrowe }
c2cf53a40a9814eb91db2cdf820f97d943f21628coar else {
4f9c22c4f27571d54197be9674e1fc0d528192aestriker ap_str_tolower(url_copy);
c2cf53a40a9814eb91db2cdf820f97d943f21628coar min_match = strlen(url_copy);
aa047239dedf0d26e8efecfade32e7337f35df19wrowe }
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
aa047239dedf0d26e8efecfade32e7337f35df19wrowe worker = (proxy_worker *)conf->workers->elts;
aa047239dedf0d26e8efecfade32e7337f35df19wrowe
aa047239dedf0d26e8efecfade32e7337f35df19wrowe /*
a9a4544168a37b43bd180b3703ccee995f27a80awrowe * Do a "longest match" on the worker name to find the worker that
a9a4544168a37b43bd180b3703ccee995f27a80awrowe * fits best to the URL, but keep in mind that we must have at least
a9a4544168a37b43bd180b3703ccee995f27a80awrowe * a minimum matching of length min_match such that
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * scheme://hostname[:port] matches between worker and url.
a9a4544168a37b43bd180b3703ccee995f27a80awrowe */
a9a4544168a37b43bd180b3703ccee995f27a80awrowe for (i = 0; i < conf->workers->nelts; i++) {
aa047239dedf0d26e8efecfade32e7337f35df19wrowe if ( ((worker_name_length = strlen(worker->name)) <= url_length)
a9a4544168a37b43bd180b3703ccee995f27a80awrowe && (worker_name_length >= min_match)
4f9c22c4f27571d54197be9674e1fc0d528192aestriker && (worker_name_length > max_match)
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar && (strncmp(url_copy, worker->name, worker_name_length) == 0) ) {
aa047239dedf0d26e8efecfade32e7337f35df19wrowe max_worker = worker;
c2cf53a40a9814eb91db2cdf820f97d943f21628coar max_match = worker_name_length;
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar }
aa047239dedf0d26e8efecfade32e7337f35df19wrowe worker++;
aa047239dedf0d26e8efecfade32e7337f35df19wrowe }
4f9c22c4f27571d54197be9674e1fc0d528192aestriker return max_worker;
aa047239dedf0d26e8efecfade32e7337f35df19wrowe}
aa047239dedf0d26e8efecfade32e7337f35df19wrowe
0540a0b469147b52e858587270dba31c2aaa9e09wrowe#if APR_HAS_THREADS
aa047239dedf0d26e8efecfade32e7337f35df19wrowestatic apr_status_t conn_pool_cleanup(void *theworker)
aa047239dedf0d26e8efecfade32e7337f35df19wrowe{
aa047239dedf0d26e8efecfade32e7337f35df19wrowe proxy_worker *worker = (proxy_worker *)theworker;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (worker->cp->res) {
aa047239dedf0d26e8efecfade32e7337f35df19wrowe worker->cp->pool = NULL;
aa047239dedf0d26e8efecfade32e7337f35df19wrowe }
aa047239dedf0d26e8efecfade32e7337f35df19wrowe return APR_SUCCESS;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
0540a0b469147b52e858587270dba31c2aaa9e09wrowe#endif
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
0540a0b469147b52e858587270dba31c2aaa9e09wrowestatic void init_conn_pool(apr_pool_t *p, proxy_worker *worker)
0540a0b469147b52e858587270dba31c2aaa9e09wrowe{
aa047239dedf0d26e8efecfade32e7337f35df19wrowe apr_pool_t *pool;
aa047239dedf0d26e8efecfade32e7337f35df19wrowe proxy_conn_pool *cp;
c2cf53a40a9814eb91db2cdf820f97d943f21628coar
c2cf53a40a9814eb91db2cdf820f97d943f21628coar /*
c2cf53a40a9814eb91db2cdf820f97d943f21628coar * Create a connection pool's subpool.
c2cf53a40a9814eb91db2cdf820f97d943f21628coar * This pool is used for connection recycling.
aa047239dedf0d26e8efecfade32e7337f35df19wrowe * Once the worker is added it is never removed but
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * it can be disabled.
aa047239dedf0d26e8efecfade32e7337f35df19wrowe */
aa047239dedf0d26e8efecfade32e7337f35df19wrowe apr_pool_create(&pool, p);
aa047239dedf0d26e8efecfade32e7337f35df19wrowe apr_pool_tag(pool, "proxy_worker_cp");
aa047239dedf0d26e8efecfade32e7337f35df19wrowe /*
0540a0b469147b52e858587270dba31c2aaa9e09wrowe * Alloc from the same pool as worker.
aa047239dedf0d26e8efecfade32e7337f35df19wrowe * proxy_conn_pool is permanently attached to the worker.
aa047239dedf0d26e8efecfade32e7337f35df19wrowe */
aa047239dedf0d26e8efecfade32e7337f35df19wrowe cp = (proxy_conn_pool *)apr_pcalloc(p, sizeof(proxy_conn_pool));
aa047239dedf0d26e8efecfade32e7337f35df19wrowe cp->pool = pool;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb worker->cp = cp;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker}
aa047239dedf0d26e8efecfade32e7337f35df19wrowe
aa047239dedf0d26e8efecfade32e7337f35df19wrowePROXY_DECLARE(const char *) ap_proxy_add_worker(proxy_worker **worker,
aa047239dedf0d26e8efecfade32e7337f35df19wrowe apr_pool_t *p,
aa047239dedf0d26e8efecfade32e7337f35df19wrowe proxy_server_conf *conf,
aa047239dedf0d26e8efecfade32e7337f35df19wrowe const char *url)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int rv;
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar apr_uri_t uri;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
aa047239dedf0d26e8efecfade32e7337f35df19wrowe rv = apr_uri_parse(p, url, &uri);
0540a0b469147b52e858587270dba31c2aaa9e09wrowe
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar if (rv != APR_SUCCESS) {
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar return "Unable to parse URL";
0540a0b469147b52e858587270dba31c2aaa9e09wrowe }
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar if (!uri.hostname || !uri.scheme) {
aa047239dedf0d26e8efecfade32e7337f35df19wrowe return "URL must be absolute!";
aa047239dedf0d26e8efecfade32e7337f35df19wrowe }
0540a0b469147b52e858587270dba31c2aaa9e09wrowe
aa047239dedf0d26e8efecfade32e7337f35df19wrowe ap_str_tolower(uri.hostname);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_str_tolower(uri.scheme);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker *worker = apr_array_push(conf->workers);
aa047239dedf0d26e8efecfade32e7337f35df19wrowe memset(*worker, 0, sizeof(proxy_worker));
aa047239dedf0d26e8efecfade32e7337f35df19wrowe (*worker)->name = apr_uri_unparse(p, &uri, APR_URI_UNP_REVEALPASSWORD);
aa047239dedf0d26e8efecfade32e7337f35df19wrowe (*worker)->scheme = uri.scheme;
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar (*worker)->hostname = uri.hostname;
aa047239dedf0d26e8efecfade32e7337f35df19wrowe (*worker)->port = uri.port;
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar (*worker)->id = proxy_lb_workers;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb (*worker)->flush_packets = flush_off;
dc8692c6c0ca616a09aa12dad005f2ef23baa1a0wrowe (*worker)->flush_wait = PROXY_FLUSH_WAIT;
a9a4544168a37b43bd180b3703ccee995f27a80awrowe (*worker)->smax = -1;
a9a4544168a37b43bd180b3703ccee995f27a80awrowe /* Increase the total worker count */
a9a4544168a37b43bd180b3703ccee995f27a80awrowe proxy_lb_workers++;
aa047239dedf0d26e8efecfade32e7337f35df19wrowe (*worker)->cp = NULL;
aa047239dedf0d26e8efecfade32e7337f35df19wrowe (*worker)->mutex = NULL;
dc8692c6c0ca616a09aa12dad005f2ef23baa1a0wrowe
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar return NULL;
aa047239dedf0d26e8efecfade32e7337f35df19wrowe}
aa047239dedf0d26e8efecfade32e7337f35df19wrowe
aa047239dedf0d26e8efecfade32e7337f35df19wrowePROXY_DECLARE(proxy_worker *) ap_proxy_create_worker(apr_pool_t *p)
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar{
aa047239dedf0d26e8efecfade32e7337f35df19wrowe
dc8692c6c0ca616a09aa12dad005f2ef23baa1a0wrowe proxy_worker *worker;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb worker = (proxy_worker *)apr_pcalloc(p, sizeof(proxy_worker));
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb worker->id = proxy_lb_workers;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb worker->smax = -1;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* Increase the total worker count */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb proxy_lb_workers++;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb worker->cp = NULL;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb worker->mutex = NULL;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return worker;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbPROXY_DECLARE(void)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbap_proxy_add_worker_to_balancer(apr_pool_t *pool, proxy_balancer *balancer,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb proxy_worker *worker)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb proxy_worker **runtime;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb runtime = apr_array_push(balancer->workers);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb *runtime = worker;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker (*runtime)->id = proxy_lb_workers;
d2220a04f870f632b8cec1e6713dbb980ed5e386wrowe /* Increase the total runtime count */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb proxy_lb_workers++;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
d2220a04f870f632b8cec1e6713dbb980ed5e386wrowe}
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbPROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
d2220a04f870f632b8cec1e6713dbb980ed5e386wrowe proxy_balancer **balancer,
d2220a04f870f632b8cec1e6713dbb980ed5e386wrowe request_rec *r,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb proxy_server_conf *conf, char **url)
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe{
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe int access_status;
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe access_status = proxy_run_pre_request(worker, balancer, r, conf, url);
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe if (access_status == DECLINED && *balancer == NULL) {
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe *worker = ap_proxy_get_worker(r->pool, conf, *url);
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe if (*worker) {
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe "proxy: %s: found worker %s for %s",
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe (*worker)->scheme, (*worker)->name, *url);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe *balancer = NULL;
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe access_status = OK;
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe }
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe else if (r->proxyreq == PROXYREQ_PROXY) {
4f9c22c4f27571d54197be9674e1fc0d528192aestriker if (conf->forward) {
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe "proxy: *: found forward proxy worker for %s",
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe *url);
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe *balancer = NULL;
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe *worker = conf->forward;
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe access_status = OK;
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe }
ebe7da316894e2b93b4a905fccd2496d0ed1bc78rbb }
ebe7da316894e2b93b4a905fccd2496d0ed1bc78rbb else if (r->proxyreq == PROXYREQ_REVERSE) {
ebe7da316894e2b93b4a905fccd2496d0ed1bc78rbb if (conf->reverse) {
ebe7da316894e2b93b4a905fccd2496d0ed1bc78rbb ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
4f9c22c4f27571d54197be9674e1fc0d528192aestriker "proxy: *: found reverse proxy worker for %s",
4f9c22c4f27571d54197be9674e1fc0d528192aestriker *url);
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe *balancer = NULL;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker *worker = conf->reverse;
e57e920838f31508f1418aa4c25ce55b345b2cebrbb access_status = OK;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker }
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe }
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe }
e57e920838f31508f1418aa4c25ce55b345b2cebrbb else if (access_status == DECLINED && *balancer != NULL) {
e57e920838f31508f1418aa4c25ce55b345b2cebrbb /* All the workers are busy */
e57e920838f31508f1418aa4c25ce55b345b2cebrbb ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
e57e920838f31508f1418aa4c25ce55b345b2cebrbb "proxy: all workers are busy. Unable to serve %s",
e57e920838f31508f1418aa4c25ce55b345b2cebrbb *url);
e57e920838f31508f1418aa4c25ce55b345b2cebrbb access_status = HTTP_SERVICE_UNAVAILABLE;
e57e920838f31508f1418aa4c25ce55b345b2cebrbb }
e57e920838f31508f1418aa4c25ce55b345b2cebrbb return access_status;
e57e920838f31508f1418aa4c25ce55b345b2cebrbb}
e57e920838f31508f1418aa4c25ce55b345b2cebrbb
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowePROXY_DECLARE(int) ap_proxy_post_request(proxy_worker *worker,
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe proxy_balancer *balancer,
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe request_rec *r,
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe proxy_server_conf *conf)
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe{
d2220a04f870f632b8cec1e6713dbb980ed5e386wrowe int access_status = OK;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker if (balancer) {
d2220a04f870f632b8cec1e6713dbb980ed5e386wrowe access_status = proxy_run_post_request(worker, balancer, r, conf);
d2220a04f870f632b8cec1e6713dbb980ed5e386wrowe if (access_status == DECLINED) {
d2220a04f870f632b8cec1e6713dbb980ed5e386wrowe access_status = OK; /* no post_request handler available */
d2220a04f870f632b8cec1e6713dbb980ed5e386wrowe /* TODO: recycle direct worker */
d2220a04f870f632b8cec1e6713dbb980ed5e386wrowe }
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe }
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return access_status;
c2cf53a40a9814eb91db2cdf820f97d943f21628coar}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/* DEPRECATED */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbPROXY_DECLARE(int) ap_proxy_connect_to_backend(apr_socket_t **newsock,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb const char *proxy_function,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb apr_sockaddr_t *backend_addr,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb const char *backend_name,
4f9c22c4f27571d54197be9674e1fc0d528192aestriker proxy_server_conf *conf,
68b29bcadd6c46aecdc9fe14c93555a2238ad2aagregames request_rec *r)
68b29bcadd6c46aecdc9fe14c93555a2238ad2aagregames{
68b29bcadd6c46aecdc9fe14c93555a2238ad2aagregames apr_status_t rv;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker int connected = 0;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker int loglevel;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb while (backend_addr && !connected) {
4f9c22c4f27571d54197be9674e1fc0d528192aestriker if ((rv = apr_socket_create(newsock, backend_addr->family,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb SOCK_STREAM, 0, r->pool)) != APR_SUCCESS) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_log_rerror(APLOG_MARK, loglevel, rv, r,
4f9c22c4f27571d54197be9674e1fc0d528192aestriker "proxy: %s: error creating fam %d socket for target %s",
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb proxy_function,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb backend_addr->family,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb backend_name);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker /*
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar * this could be an IPv6 address from the DNS but the
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * local machine won't give us an IPv6 socket; hopefully the
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar * DNS returned an additional address to try
4f9c22c4f27571d54197be9674e1fc0d528192aestriker */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb backend_addr = backend_addr->next;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker continue;
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar }
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (conf->recv_buffer_size > 0 &&
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar (rv = apr_socket_opt_set(*newsock, APR_SO_RCVBUF,
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar conf->recv_buffer_size))) {
4f9c22c4f27571d54197be9674e1fc0d528192aestriker ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb "apr_socket_opt_set(SO_RCVBUF): Failed to set "
4f9c22c4f27571d54197be9674e1fc0d528192aestriker "ProxyReceiveBufferSize, using default");
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe rv = apr_socket_opt_set(*newsock, APR_TCP_NODELAY, 1);
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe "apr_socket_opt_set(APR_TCP_NODELAY): "
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb "Failed to set");
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe }
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe /* Set a timeout on the socket */
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe if (conf->timeout_set == 1) {
d2220a04f870f632b8cec1e6713dbb980ed5e386wrowe apr_socket_timeout_set(*newsock, conf->timeout);
b45c1c292ff1fa635004ae81fa691f8cb3cdda85rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb apr_socket_timeout_set(*newsock, r->server->timeout);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb "proxy: %s: fam %d socket created to connect to %s",
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar proxy_function, backend_addr->family, backend_name);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* make the connection out of the socket */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb rv = apr_socket_connect(*newsock, backend_addr);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* if an error occurred, loop round and try again */
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddard if (rv != APR_SUCCESS) {
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddard apr_socket_close(*newsock);
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddard loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddard ap_log_rerror(APLOG_MARK, loglevel, rv, r,
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddard "proxy: %s: attempt to connect to %pI (%s) failed",
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb proxy_function,
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddard backend_addr,
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddard backend_name);
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddard backend_addr = backend_addr->next;
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddard continue;
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddard }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb connected = 1;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return connected ? 0 : 1;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic apr_status_t connection_cleanup(void *theconn)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb proxy_conn_rec *conn = (proxy_conn_rec *)theconn;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb proxy_worker *worker = conn->worker;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /*
efa1a34b0a7785fc72863eff175b0cfc1ecb0e38wrowe * If the connection pool is NULL the worker
117026201e6d8fe7d82416b8a7324830f5a87292wrowe * cleanup has been run. Just return.
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe */
117026201e6d8fe7d82416b8a7324830f5a87292wrowe if (!worker->cp) {
117026201e6d8fe7d82416b8a7324830f5a87292wrowe return APR_SUCCESS;
117026201e6d8fe7d82416b8a7324830f5a87292wrowe }
117026201e6d8fe7d82416b8a7324830f5a87292wrowe
117026201e6d8fe7d82416b8a7324830f5a87292wrowe#if APR_HAS_THREADS
6c24fd6cfe148639988d5b335185ffb215662801wrowe /* Sanity check: Did we already return the pooled connection? */
117026201e6d8fe7d82416b8a7324830f5a87292wrowe if (conn->inreslist) {
d2220a04f870f632b8cec1e6713dbb980ed5e386wrowe ap_log_perror(APLOG_MARK, APLOG_ERR, 0, conn->pool,
117026201e6d8fe7d82416b8a7324830f5a87292wrowe "proxy: Pooled connection 0x%pp for worker %s has been"
4f9c22c4f27571d54197be9674e1fc0d528192aestriker " already returned to the connection pool.", conn,
cadddb2c31d24d48f4017db4df0a29687432326cwrowe worker->name);
117026201e6d8fe7d82416b8a7324830f5a87292wrowe return APR_SUCCESS;
f888346b48f5e5b5e3f0a47dedb8cefd2759a4e2gregames }
f888346b48f5e5b5e3f0a47dedb8cefd2759a4e2gregames#endif
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe
4f9c22c4f27571d54197be9674e1fc0d528192aestriker /* determine if the connection need to be closed */
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe if (conn->close || !worker->is_address_reusable || worker->disablereuse) {
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe apr_pool_t *p = conn->pool;
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe apr_pool_clear(p);
f888346b48f5e5b5e3f0a47dedb8cefd2759a4e2gregames conn = apr_pcalloc(p, sizeof(proxy_conn_rec));
f888346b48f5e5b5e3f0a47dedb8cefd2759a4e2gregames conn->pool = p;
f888346b48f5e5b5e3f0a47dedb8cefd2759a4e2gregames conn->worker = worker;
f888346b48f5e5b5e3f0a47dedb8cefd2759a4e2gregames apr_pool_create(&(conn->scpool), p);
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe apr_pool_tag(conn->scpool, "proxy_conn_scpool");
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe }
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe#if APR_HAS_THREADS
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe if (worker->hmax && worker->cp->res) {
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe conn->inreslist = 1;
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe apr_reslist_release(worker->cp->res, (void *)conn);
f888346b48f5e5b5e3f0a47dedb8cefd2759a4e2gregames }
f888346b48f5e5b5e3f0a47dedb8cefd2759a4e2gregames else
f888346b48f5e5b5e3f0a47dedb8cefd2759a4e2gregames#endif
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe {
f888346b48f5e5b5e3f0a47dedb8cefd2759a4e2gregames worker->cp->conn = conn;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker }
cadddb2c31d24d48f4017db4df0a29687432326cwrowe
117026201e6d8fe7d82416b8a7324830f5a87292wrowe /* Always return the SUCCESS */
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar return APR_SUCCESS;
e7505ba54ac56ae30e4e250f912f3dbaf92ca45fwrowe}
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar
4f9c22c4f27571d54197be9674e1fc0d528192aestrikerstatic void socket_cleanup(proxy_conn_rec *conn)
cadddb2c31d24d48f4017db4df0a29687432326cwrowe{
4f9c22c4f27571d54197be9674e1fc0d528192aestriker conn->sock = NULL;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker conn->connection = NULL;
cadddb2c31d24d48f4017db4df0a29687432326cwrowe apr_pool_clear(conn->scpool);
5b3abd2fecc712f08ad728114aa77137b9f67716wrowe}
85bb5b92490e4f095aae394118fc588a8f4c486fwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowePROXY_DECLARE(apr_status_t) ap_proxy_ssl_connection_cleanup(proxy_conn_rec *conn,
efa1a34b0a7785fc72863eff175b0cfc1ecb0e38wrowe request_rec *r)
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe{
beda1fb2f11c52ca4612460a5d5ba47398143efbwrowe apr_bucket_brigade *bb;
beda1fb2f11c52ca4612460a5d5ba47398143efbwrowe apr_status_t rv;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker
4f9c22c4f27571d54197be9674e1fc0d528192aestriker /*
beda1fb2f11c52ca4612460a5d5ba47398143efbwrowe * If we have an existing SSL connection it might be possible that the
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe * server sent some SSL message we have not read so far (e.g. a SSL
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe * shutdown message if the server closed the keepalive connection while
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe * the connection was held unused in our pool).
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe * So ensure that if present (=> APR_NONBLOCK_READ) it is read and
c2cf53a40a9814eb91db2cdf820f97d943f21628coar * processed. We don't expect any data to be in the returned brigade.
c2cf53a40a9814eb91db2cdf820f97d943f21628coar */
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe if (conn->sock && conn->connection) {
c2cf53a40a9814eb91db2cdf820f97d943f21628coar bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
117026201e6d8fe7d82416b8a7324830f5a87292wrowe rv = ap_get_brigade(conn->connection->input_filters, bb,
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar AP_MODE_READBYTES, APR_NONBLOCK_READ,
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe HUGE_STRING_LEN);
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe if ((rv != APR_SUCCESS) && !APR_STATUS_IS_EAGAIN(rv)) {
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar socket_cleanup(conn);
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe }
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar if (!APR_BRIGADE_EMPTY(bb)) {
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar apr_off_t len;
117026201e6d8fe7d82416b8a7324830f5a87292wrowe
117026201e6d8fe7d82416b8a7324830f5a87292wrowe rv = apr_brigade_length(bb, 0, &len);
c2cf53a40a9814eb91db2cdf820f97d943f21628coar ap_log_rerror(APLOG_MARK, APLOG_TRACE3, rv, r,
117026201e6d8fe7d82416b8a7324830f5a87292wrowe "proxy: SSL cleanup brigade contained %"
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe APR_OFF_T_FMT " bytes of data.", len);
cadddb2c31d24d48f4017db4df0a29687432326cwrowe }
cadddb2c31d24d48f4017db4df0a29687432326cwrowe apr_brigade_destroy(bb);
cadddb2c31d24d48f4017db4df0a29687432326cwrowe }
cadddb2c31d24d48f4017db4df0a29687432326cwrowe return APR_SUCCESS;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker}
c2cf53a40a9814eb91db2cdf820f97d943f21628coar
c2cf53a40a9814eb91db2cdf820f97d943f21628coar/* reslist constructor */
cadddb2c31d24d48f4017db4df0a29687432326cwrowestatic apr_status_t connection_constructor(void **resource, void *params,
cadddb2c31d24d48f4017db4df0a29687432326cwrowe apr_pool_t *pool)
cadddb2c31d24d48f4017db4df0a29687432326cwrowe{
cadddb2c31d24d48f4017db4df0a29687432326cwrowe apr_pool_t *ctx;
cadddb2c31d24d48f4017db4df0a29687432326cwrowe apr_pool_t *scpool;
cadddb2c31d24d48f4017db4df0a29687432326cwrowe proxy_conn_rec *conn;
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe proxy_worker *worker = (proxy_worker *)params;
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe
cadddb2c31d24d48f4017db4df0a29687432326cwrowe /*
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe * Create the subpool for each connection
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe * This keeps the memory consumption constant
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe * when disconnecting from backend.
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar */
cadddb2c31d24d48f4017db4df0a29687432326cwrowe apr_pool_create(&ctx, pool);
cadddb2c31d24d48f4017db4df0a29687432326cwrowe apr_pool_tag(ctx, "proxy_conn_pool");
4f9c22c4f27571d54197be9674e1fc0d528192aestriker /*
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe * Create another subpool that manages the data for the
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe * socket and the connection member of the proxy_conn_rec struct as we
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * destroy this data more frequently than other data in the proxy_conn_rec
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * struct like hostname and addr (at least in the case where we have
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe * keepalive connections that timed out).
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe */
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe apr_pool_create(&scpool, ctx);
3cd826b00280881e5a2f03d8ec1f8d55802b93dewrowe apr_pool_tag(scpool, "proxy_conn_scpool");
cadddb2c31d24d48f4017db4df0a29687432326cwrowe conn = apr_pcalloc(ctx, sizeof(proxy_conn_rec));
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe conn->pool = ctx;
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe conn->scpool = scpool;
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe conn->worker = worker;
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe#if APR_HAS_THREADS
117026201e6d8fe7d82416b8a7324830f5a87292wrowe conn->inreslist = 1;
117026201e6d8fe7d82416b8a7324830f5a87292wrowe#endif
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe *resource = conn;
c2cf53a40a9814eb91db2cdf820f97d943f21628coar
c2cf53a40a9814eb91db2cdf820f97d943f21628coar return APR_SUCCESS;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#if APR_HAS_THREADS /* only needed when threads are used */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/* reslist destructor */
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowestatic apr_status_t connection_destructor(void *resource, void *params,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb apr_pool_t *pool)
d2220a04f870f632b8cec1e6713dbb980ed5e386wrowe{
b45c1c292ff1fa635004ae81fa691f8cb3cdda85rbb proxy_conn_rec *conn = (proxy_conn_rec *)resource;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe /* Destroy the pool only if not called from reslist_destroy */
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe if (conn->worker->cp->pool) {
ecc4a080f07af3fbc1b91bbd00997ec1d592c6f9wrowe apr_pool_destroy(conn->pool);
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe }
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar
2d2dadb81bf34e3bc9321eabcd971a738431b364wrowe return APR_SUCCESS;
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar}
4f9c22c4f27571d54197be9674e1fc0d528192aestriker#endif
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe/*
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe * ap_proxy_initialize_worker_share() concerns itself
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe * with initializing those parts of worker which
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe * are, or could be, shared. Basically worker->s
4f9c22c4f27571d54197be9674e1fc0d528192aestriker */
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoarPROXY_DECLARE(void) ap_proxy_initialize_worker_share(proxy_server_conf *conf,
ecc4a080f07af3fbc1b91bbd00997ec1d592c6f9wrowe proxy_worker *worker,
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar server_rec *s)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb proxy_worker_stat *score = NULL;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
4f9c22c4f27571d54197be9674e1fc0d528192aestriker if (PROXY_WORKER_IS_INITIALIZED(worker)) {
5b3abd2fecc712f08ad728114aa77137b9f67716wrowe /* The worker share is already initialized */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb "proxy: worker %s already initialized",
af7e32b660b02a378e91d40987e59b28864db954jwoolley worker->name);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker return;
c2cf53a40a9814eb91db2cdf820f97d943f21628coar }
0540a0b469147b52e858587270dba31c2aaa9e09wrowe if (!worker->s) {
0540a0b469147b52e858587270dba31c2aaa9e09wrowe /* Get scoreboard slot */
0540a0b469147b52e858587270dba31c2aaa9e09wrowe if (ap_scoreboard_image) {
c2cf53a40a9814eb91db2cdf820f97d943f21628coar score = (proxy_worker_stat *) ap_get_scoreboard_lb(worker->id);
c2cf53a40a9814eb91db2cdf820f97d943f21628coar if (!score) {
0540a0b469147b52e858587270dba31c2aaa9e09wrowe ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
c2cf53a40a9814eb91db2cdf820f97d943f21628coar "proxy: ap_get_scoreboard_lb(%d) failed in child %" APR_PID_T_FMT " for worker %s",
0540a0b469147b52e858587270dba31c2aaa9e09wrowe worker->id, getpid(), worker->name);
0540a0b469147b52e858587270dba31c2aaa9e09wrowe }
0540a0b469147b52e858587270dba31c2aaa9e09wrowe else {
0540a0b469147b52e858587270dba31c2aaa9e09wrowe ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s,
c2cf53a40a9814eb91db2cdf820f97d943f21628coar "proxy: grabbed scoreboard slot %d in child %" APR_PID_T_FMT " for worker %s",
0540a0b469147b52e858587270dba31c2aaa9e09wrowe worker->id, getpid(), worker->name);
c2cf53a40a9814eb91db2cdf820f97d943f21628coar }
0540a0b469147b52e858587270dba31c2aaa9e09wrowe }
7763a4beb8afca9c8f93db0cb6836124901af52awrowe if (!score) {
0540a0b469147b52e858587270dba31c2aaa9e09wrowe score = (proxy_worker_stat *) apr_pcalloc(conf->pool, sizeof(proxy_worker_stat));
0540a0b469147b52e858587270dba31c2aaa9e09wrowe ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s,
c2cf53a40a9814eb91db2cdf820f97d943f21628coar "proxy: initialized plain memory in child %" APR_PID_T_FMT " for worker %s",
c2cf53a40a9814eb91db2cdf820f97d943f21628coar getpid(), worker->name);
0540a0b469147b52e858587270dba31c2aaa9e09wrowe }
0540a0b469147b52e858587270dba31c2aaa9e09wrowe worker->s = score;
0540a0b469147b52e858587270dba31c2aaa9e09wrowe /*
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz * recheck to see if we've already been here. Possible
0540a0b469147b52e858587270dba31c2aaa9e09wrowe * if proxy is using scoreboard to hold shared stats
0540a0b469147b52e858587270dba31c2aaa9e09wrowe */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (PROXY_WORKER_IS_INITIALIZED(worker)) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* The worker share is already initialized */
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s,
5b3abd2fecc712f08ad728114aa77137b9f67716wrowe "proxy: worker %s already initialized",
5b3abd2fecc712f08ad728114aa77137b9f67716wrowe worker->name);
5b3abd2fecc712f08ad728114aa77137b9f67716wrowe return;
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (worker->route) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb strcpy(worker->s->route, worker->route);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else {
58097d7d8d1a394092374b9f6ddf76b7993724a4rbb *worker->s->route = '\0';
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (worker->redirect) {
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe strcpy(worker->s->redirect, worker->redirect);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else {
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe *worker->s->redirect = '\0';
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb worker->s->status |= (worker->status | PROXY_WORKER_INITIALIZED);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddard
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddardPROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, server_rec *s, apr_pool_t *p)
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddard{
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddard apr_status_t rv;
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddard
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddard#if APR_HAS_THREADS
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddard int mpm_threads;
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddard#endif
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddard
66e89b91046a4d0998bcb11c8aeb39ac444ed2dfjerenkrantz if (worker->status & PROXY_WORKER_INITIALIZED) {
66e89b91046a4d0998bcb11c8aeb39ac444ed2dfjerenkrantz /* The worker is already initialized */
66e89b91046a4d0998bcb11c8aeb39ac444ed2dfjerenkrantz return APR_SUCCESS;
30b4a330a5f651eb5198fa93dbb9f3d3594564c9stoddard }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* Set default parameters */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (!worker->retry_set) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb worker->retry = apr_time_from_sec(PROXY_WORKER_DEFAULT_RETRY);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* By default address is reusable unless DisableReuse is set */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (worker->disablereuse) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb worker->is_address_reusable = 0;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb worker->is_address_reusable = 1;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (worker->cp == NULL)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb init_conn_pool(p, worker);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (worker->cp == NULL) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz "can not create connection pool");
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return APR_EGENERAL;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#if APR_HAS_THREADS
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (worker->mutex == NULL) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb rv = apr_thread_mutex_create(&(worker->mutex), APR_THREAD_MUTEX_DEFAULT, p);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (rv != APR_SUCCESS) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
4f9c22c4f27571d54197be9674e1fc0d528192aestriker "can not create thread mutex");
4f9c22c4f27571d54197be9674e1fc0d528192aestriker return rv;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker }
}
ap_mpm_query(AP_MPMQ_MAX_THREADS, &mpm_threads);
if (mpm_threads > 1) {
/* Set hard max to no more then mpm_threads */
if (worker->hmax == 0 || worker->hmax > mpm_threads) {
worker->hmax = mpm_threads;
}
if (worker->smax == -1 || worker->smax > worker->hmax) {
worker->smax = worker->hmax;
}
/* Set min to be lower then smax */
if (worker->min > worker->smax) {
worker->min = worker->smax;
}
}
else {
/* This will supress the apr_reslist creation */
worker->min = worker->smax = worker->hmax = 0;
}
if (worker->hmax) {
rv = apr_reslist_create(&(worker->cp->res),
worker->min, worker->smax,
worker->hmax, worker->ttl,
connection_constructor, connection_destructor,
worker, worker->cp->pool);
apr_pool_cleanup_register(worker->cp->pool, (void *)worker,
conn_pool_cleanup,
apr_pool_cleanup_null);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"proxy: initialized worker %d in child %" APR_PID_T_FMT " for (%s) min=%d max=%d smax=%d",
worker->id, getpid(), worker->hostname, worker->min,
worker->hmax, worker->smax);
#if (APR_MAJOR_VERSION > 0)
/* Set the acquire timeout */
if (rv == APR_SUCCESS && worker->acquire_set) {
apr_reslist_timeout_set(worker->cp->res, worker->acquire);
}
#endif
}
else
#endif
{
void *conn;
rv = connection_constructor(&conn, worker, worker->cp->pool);
worker->cp->conn = conn;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"proxy: initialized single connection worker %d in child %" APR_PID_T_FMT " for (%s)",
worker->id, getpid(), worker->hostname);
}
if (rv == APR_SUCCESS) {
worker->status |= (PROXY_WORKER_INITIALIZED);
}
return rv;
}
PROXY_DECLARE(int) ap_proxy_retry_worker(const char *proxy_function,
proxy_worker *worker,
server_rec *s)
{
if (worker->s->status & PROXY_WORKER_IN_ERROR) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"proxy: %s: retrying the worker for (%s)",
proxy_function, worker->hostname);
if (apr_time_now() > worker->s->error_time + worker->retry) {
++worker->s->retries;
worker->s->status &= ~PROXY_WORKER_IN_ERROR;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"proxy: %s: worker for (%s) has been marked for retry",
proxy_function, worker->hostname);
return OK;
}
else {
return DECLINED;
}
}
else {
return OK;
}
}
PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function,
proxy_conn_rec **conn,
proxy_worker *worker,
server_rec *s)
{
apr_status_t rv;
if (!PROXY_WORKER_IS_USABLE(worker)) {
/* Retry the worker */
ap_proxy_retry_worker(proxy_function, worker, s);
if (!PROXY_WORKER_IS_USABLE(worker)) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
"proxy: %s: disabled connection for (%s)",
proxy_function, worker->hostname);
return HTTP_SERVICE_UNAVAILABLE;
}
}
#if APR_HAS_THREADS
if (worker->hmax && worker->cp->res) {
rv = apr_reslist_acquire(worker->cp->res, (void **)conn);
}
else
#endif
{
/* create the new connection if the previous was destroyed */
if (!worker->cp->conn) {
connection_constructor((void **)conn, worker, worker->cp->pool);
}
else {
*conn = worker->cp->conn;
worker->cp->conn = NULL;
}
rv = APR_SUCCESS;
}
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
"proxy: %s: failed to acquire connection for (%s)",
proxy_function, worker->hostname);
return HTTP_SERVICE_UNAVAILABLE;
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"proxy: %s: has acquired connection for (%s)",
proxy_function, worker->hostname);
(*conn)->worker = worker;
(*conn)->close = 0;
#if APR_HAS_THREADS
(*conn)->inreslist = 0;
#endif
return OK;
}
PROXY_DECLARE(int) ap_proxy_release_connection(const char *proxy_function,
proxy_conn_rec *conn,
server_rec *s)
{
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"proxy: %s: has released connection for (%s)",
proxy_function, conn->worker->hostname);
connection_cleanup(conn);
return OK;
}
PROXY_DECLARE(int)
ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
proxy_server_conf *conf,
proxy_worker *worker,
proxy_conn_rec *conn,
apr_uri_t *uri,
char **url,
const char *proxyname,
apr_port_t proxyport,
char *server_portstr,
int server_portstr_size)
{
int server_port;
apr_status_t err = APR_SUCCESS;
apr_status_t uerr = APR_SUCCESS;
/*
* Break up the URL to determine the host to connect to
*/
/* we break the URL into host, port, uri */
if (APR_SUCCESS != apr_uri_parse(p, *url, uri)) {
return ap_proxyerror(r, HTTP_BAD_REQUEST,
apr_pstrcat(p,"URI cannot be parsed: ", *url,
NULL));
}
if (!uri->port) {
uri->port = apr_uri_port_of_scheme(uri->scheme);
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"proxy: connecting %s to %s:%d", *url, uri->hostname,
uri->port);
/*
* allocate these out of the specified connection pool
* The scheme handler decides if this is permanent or
* short living pool.
*/
/* are we connecting directly, or via a proxy? */
if (!proxyname) {
*url = apr_pstrcat(p, uri->path, uri->query ? "?" : "",
uri->query ? uri->query : "",
uri->fragment ? "#" : "",
uri->fragment ? uri->fragment : "", NULL);
}
/*
* Make sure that we pick the the correct and valid worker.
* If a single keepalive connection triggers different workers,
* then we have a problem (we don't select the correct one).
* Do an expensive check in this case, where we compare the
* the hostnames associated between the two.
*
* TODO: Handle this much better...
*/
if (!conn->hostname || !worker->is_address_reusable ||
worker->disablereuse ||
(r->connection->keepalives &&
(r->proxyreq == PROXYREQ_PROXY || r->proxyreq == PROXYREQ_REVERSE) &&
(strcasecmp(conn->hostname, uri->hostname) != 0) ) ) {
if (proxyname) {
conn->hostname = apr_pstrdup(conn->pool, proxyname);
conn->port = proxyport;
/*
* If we have a forward proxy and the protocol is HTTPS,
* then we need to prepend a HTTP CONNECT request before
* sending our actual HTTPS requests.
* Save our real backend data for using it later during HTTP CONNECT.
*/
if (conn->is_ssl) {
const char *proxy_auth;
forward_info *forward = apr_pcalloc(conn->pool, sizeof(forward_info));
conn->forward = forward;
forward->use_http_connect = 1;
forward->target_host = apr_pstrdup(conn->pool, uri->hostname);
forward->target_port = uri->port;
/* Do we want to pass Proxy-Authorization along?
* If we haven't used it, then YES
* If we have used it then MAYBE: RFC2616 says we MAY propagate it.
* So let's make it configurable by env.
* The logic here is the same used in mod_proxy_http.
*/
proxy_auth = apr_table_get(r->headers_in, "Proxy-Authorization");
if (proxy_auth != NULL &&
proxy_auth[0] != '\0' &&
r->user == NULL && /* we haven't yet authenticated */
apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) {
forward->proxy_auth = apr_pstrdup(conn->pool, proxy_auth);
}
}
}
else {
conn->hostname = apr_pstrdup(conn->pool, uri->hostname);
conn->port = uri->port;
}
socket_cleanup(conn);
err = apr_sockaddr_info_get(&(conn->addr),
conn->hostname, APR_UNSPEC,
conn->port, 0,
conn->pool);
}
else if (!worker->cp->addr) {
if ((err = PROXY_THREAD_LOCK(worker)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server,
"proxy: lock");
return HTTP_INTERNAL_SERVER_ERROR;
}
/*
* Worker can have the single constant backend adress.
* The single DNS lookup is used once per worker.
* If dynamic change is needed then set the addr to NULL
* inside dynamic config to force the lookup.
*/
err = apr_sockaddr_info_get(&(worker->cp->addr),
conn->hostname, APR_UNSPEC,
conn->port, 0,
worker->cp->pool);
conn->addr = worker->cp->addr;
if ((uerr = PROXY_THREAD_UNLOCK(worker)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, uerr, r->server,
"proxy: unlock");
}
}
else {
conn->addr = worker->cp->addr;
}
/* Close a possible existing socket if we are told to do so */
if (conn->close) {
socket_cleanup(conn);
conn->close = 0;
}
if (err != APR_SUCCESS) {
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
apr_pstrcat(p, "DNS lookup failure for: ",
conn->hostname, NULL));
}
/* Get the server port for the Via headers */
{
server_port = ap_get_server_port(r);
if (ap_is_default_port(server_port, r)) {
strcpy(server_portstr,"");
}
else {
apr_snprintf(server_portstr, server_portstr_size, ":%d",
server_port);
}
}
/* check if ProxyBlock directive on this host */
if (OK != ap_proxy_checkproxyblock(r, conf, conn->addr)) {
return ap_proxyerror(r, HTTP_FORBIDDEN,
"Connect to remote machine blocked");
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"proxy: connected %s to %s:%d", *url, conn->hostname,
conn->port);
return OK;
}
#define USE_ALTERNATE_IS_CONNECTED 1
#if !defined(APR_MSG_PEEK) && defined(MSG_PEEK)
#define APR_MSG_PEEK MSG_PEEK
#endif
#if USE_ALTERNATE_IS_CONNECTED && defined(APR_MSG_PEEK)
static int is_socket_connected(apr_socket_t *socket)
{
apr_pollfd_t pfds[1];
apr_status_t status;
apr_int32_t nfds;
pfds[0].reqevents = APR_POLLIN;
pfds[0].desc_type = APR_POLL_SOCKET;
pfds[0].desc.s = socket;
do {
status = apr_poll(&pfds[0], 1, &nfds, 0);
} while (APR_STATUS_IS_EINTR(status));
if (status == APR_SUCCESS && nfds == 1 &&
pfds[0].rtnevents == APR_POLLIN) {
apr_sockaddr_t unused;
apr_size_t len = 1;
char buf[1];
/* The socket might be closed in which case
* the poll will return POLLIN.
* If there is no data available the socket
* is closed.
*/
status = apr_socket_recvfrom(&unused, socket, APR_MSG_PEEK,
&buf[0], &len);
if (status == APR_SUCCESS && len)
return 1;
else
return 0;
}
else if (APR_STATUS_IS_EAGAIN(status) || APR_STATUS_IS_TIMEUP(status)) {
return 1;
}
return 0;
}
#else
static int is_socket_connected(apr_socket_t *sock)
{
apr_size_t buffer_len = 1;
char test_buffer[1];
apr_status_t socket_status;
apr_interval_time_t current_timeout;
/* save timeout */
apr_socket_timeout_get(sock, &current_timeout);
/* set no timeout */
apr_socket_timeout_set(sock, 0);
socket_status = apr_socket_recv(sock, test_buffer, &buffer_len);
/* put back old timeout */
apr_socket_timeout_set(sock, current_timeout);
if (APR_STATUS_IS_EOF(socket_status)
|| APR_STATUS_IS_ECONNRESET(socket_status)) {
return 0;
}
else {
return 1;
}
}
#endif /* USE_ALTERNATE_IS_CONNECTED */
/*
* Send a HTTP CONNECT request to a forward proxy.
* The proxy is given by "backend", the target server
* is contained in the "forward" member of "backend".
*/
static apr_status_t send_http_connect(proxy_conn_rec *backend,
server_rec *s)
{
int status;
apr_size_t nbytes;
apr_size_t left;
int complete = 0;
char buffer[HUGE_STRING_LEN];
char drain_buffer[HUGE_STRING_LEN];
forward_info *forward = (forward_info *)backend->forward;
int len = 0;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"proxy: CONNECT: sending the CONNECT request for %s:%d "
"to the remote proxy %pI (%s)",
forward->target_host, forward->target_port,
backend->addr, backend->hostname);
/* Create the CONNECT request */
nbytes = apr_snprintf(buffer, sizeof(buffer),
"CONNECT %s:%d HTTP/1.0" CRLF,
forward->target_host, forward->target_port);
/* Add proxy authorization from the initial request if necessary */
if (forward->proxy_auth != NULL) {
nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes,
"Proxy-Authorization: %s" CRLF,
forward->proxy_auth);
}
/* Set a reasonable agent and send everything */
nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes,
"Proxy-agent: %s" CRLF CRLF,
ap_get_server_banner());
apr_socket_send(backend->sock, buffer, &nbytes);
/* Receive the whole CONNECT response */
left = sizeof(buffer) - 1;
/* Read until we find the end of the headers or run out of buffer */
do {
nbytes = left;
status = apr_socket_recv(backend->sock, buffer + len, &nbytes);
len += nbytes;
left -= nbytes;
buffer[len] = '\0';
if (strstr(buffer + len - nbytes, "\r\n\r\n") != NULL) {
complete = 1;
break;
}
} while (status == APR_SUCCESS && left > 0);
/* Drain what's left */
if (!complete) {
nbytes = sizeof(drain_buffer) - 1;
while (status == APR_SUCCESS && nbytes) {
status = apr_socket_recv(backend->sock, drain_buffer, &nbytes);
buffer[nbytes] = '\0';
nbytes = sizeof(drain_buffer) - 1;
if (strstr(drain_buffer, "\r\n\r\n") != NULL) {
complete = 1;
break;
}
}
}
/* Check for HTTP_OK response status */
if (status == APR_SUCCESS) {
int major, minor;
/* Only scan for three character status code */
char code_str[4];
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"send_http_connect: response from the forward proxy: %s",
buffer);
/* Extract the returned code */
if (sscanf(buffer, "HTTP/%u.%u %3s", &major, &minor, code_str) == 3) {
status = atoi(code_str);
if (status == HTTP_OK) {
status = APR_SUCCESS;
}
else {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
"send_http_connect: the forward proxy returned code is '%s'",
code_str);
status = APR_INCOMPLETE;
}
}
}
return(status);
}
PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
proxy_conn_rec *conn,
proxy_worker *worker,
server_rec *s)
{
apr_status_t rv;
int connected = 0;
int loglevel;
apr_sockaddr_t *backend_addr = conn->addr;
apr_socket_t *newsock;
void *sconf = s->module_config;
proxy_server_conf *conf =
(proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
if (conn->sock) {
if (!(connected = is_socket_connected(conn->sock))) {
socket_cleanup(conn);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"proxy: %s: backend socket is disconnected.",
proxy_function);
}
}
while (backend_addr && !connected) {
if ((rv = apr_socket_create(&newsock, backend_addr->family,
SOCK_STREAM, APR_PROTO_TCP,
conn->scpool)) != APR_SUCCESS) {
loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
ap_log_error(APLOG_MARK, loglevel, rv, s,
"proxy: %s: error creating fam %d socket for target %s",
proxy_function,
backend_addr->family,
worker->hostname);
/*
* this could be an IPv6 address from the DNS but the
* local machine won't give us an IPv6 socket; hopefully the
* DNS returned an additional address to try
*/
backend_addr = backend_addr->next;
continue;
}
conn->connection = NULL;
if (worker->recv_buffer_size > 0 &&
(rv = apr_socket_opt_set(newsock, APR_SO_RCVBUF,
worker->recv_buffer_size))) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
"apr_socket_opt_set(SO_RCVBUF): Failed to set "
"ProxyReceiveBufferSize, using default");
}
rv = apr_socket_opt_set(newsock, APR_TCP_NODELAY, 1);
if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
"apr_socket_opt_set(APR_TCP_NODELAY): "
"Failed to set");
}
/* Set a timeout for connecting to the backend on the socket */
if (worker->conn_timeout_set) {
apr_socket_timeout_set(newsock, worker->conn_timeout);
}
else if (worker->timeout_set == 1) {
apr_socket_timeout_set(newsock, worker->timeout);
}
else if (conf->timeout_set == 1) {
apr_socket_timeout_set(newsock, conf->timeout);
}
else {
apr_socket_timeout_set(newsock, s->timeout);
}
/* Set a keepalive option */
if (worker->keepalive) {
if ((rv = apr_socket_opt_set(newsock,
APR_SO_KEEPALIVE, 1)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
"apr_socket_opt_set(SO_KEEPALIVE): Failed to set"
" Keepalive");
}
}
ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, s,
"proxy: %s: fam %d socket created to connect to %s",
proxy_function, backend_addr->family, worker->hostname);
/* make the connection out of the socket */
rv = apr_socket_connect(newsock, backend_addr);
/* if an error occurred, loop round and try again */
if (rv != APR_SUCCESS) {
apr_socket_close(newsock);
loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
ap_log_error(APLOG_MARK, loglevel, rv, s,
"proxy: %s: attempt to connect to %pI (%s) failed",
proxy_function,
backend_addr,
worker->hostname);
backend_addr = backend_addr->next;
continue;
}
/* Set a timeout on the socket */
if (worker->timeout_set == 1) {
apr_socket_timeout_set(newsock, worker->timeout);
}
else if (conf->timeout_set == 1) {
apr_socket_timeout_set(newsock, conf->timeout);
}
else {
apr_socket_timeout_set(newsock, s->timeout);
}
conn->sock = newsock;
if (conn->forward) {
forward_info *forward = (forward_info *)conn->forward;
/*
* For HTTP CONNECT we need to prepend CONNECT request before
* sending our actual HTTPS requests.
*/
if (forward->use_http_connect) {
rv = send_http_connect(conn, s);
/* If an error occurred, loop round and try again */
if (rv != APR_SUCCESS) {
conn->sock = NULL;
apr_socket_close(newsock);
loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
ap_log_error(APLOG_MARK, loglevel, rv, s,
"proxy: %s: attempt to connect to %s:%d "
"via http CONNECT through %pI (%s) failed",
proxy_function,
forward->target_host, forward->target_port,
backend_addr, worker->hostname);
backend_addr = backend_addr->next;
continue;
}
}
}
connected = 1;
}
/*
* Put the entire worker to error state if
* the PROXY_WORKER_IGNORE_ERRORS flag is not set.
* Altrough some connections may be alive
* no further connections to the worker could be made
*/
if (!connected && PROXY_WORKER_IS_USABLE(worker) &&
!(worker->s->status & PROXY_WORKER_IGNORE_ERRORS)) {
worker->s->status |= PROXY_WORKER_IN_ERROR;
worker->s->error_time = apr_time_now();
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
"ap_proxy_connect_backend disabling worker for (%s)",
worker->hostname);
}
else {
if (worker->s->retries) {
/*
* A worker came back. So here is where we need to
* either reset all params to initial conditions or
* apply some sort of aging
*/
}
worker->s->error_time = 0;
worker->s->retries = 0;
}
return connected ? OK : DECLINED;
}
PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function,
proxy_conn_rec *conn,
conn_rec *c,
server_rec *s)
{
apr_sockaddr_t *backend_addr = conn->addr;
int rc;
apr_interval_time_t current_timeout;
apr_bucket_alloc_t *bucket_alloc;
if (conn->connection) {
return OK;
}
bucket_alloc = apr_bucket_alloc_create(conn->scpool);
/*
* The socket is now open, create a new backend server connection
*/
conn->connection = ap_run_create_connection(conn->scpool, s, conn->sock,
0, NULL,
bucket_alloc);
if (!conn->connection) {
/*
* the peer reset the connection already; ap_run_create_connection()
* closed the socket
*/
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
s, "proxy: %s: an error occurred creating a "
"new connection to %pI (%s)", proxy_function,
backend_addr, conn->hostname);
/* XXX: Will be closed when proxy_conn is closed */
socket_cleanup(conn);
return HTTP_INTERNAL_SERVER_ERROR;
}
/* For ssl connection to backend */
if (conn->is_ssl) {
if (!ap_proxy_ssl_enable(conn->connection)) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0,
s, "proxy: %s: failed to enable ssl support "
"for %pI (%s)", proxy_function,
backend_addr, conn->hostname);
return HTTP_INTERNAL_SERVER_ERROR;
}
}
else {
/* TODO: See if this will break FTP */
ap_proxy_ssl_disable(conn->connection);
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"proxy: %s: connection complete to %pI (%s)",
proxy_function, backend_addr, conn->hostname);
/*
* save the timeout of the socket because core_pre_connection
* will set it to base_server->timeout
* (core TimeOut directive).
*/
apr_socket_timeout_get(conn->sock, &current_timeout);
/* set up the connection filters */
rc = ap_run_pre_connection(conn->connection, conn->sock);
if (rc != OK && rc != DONE) {
conn->connection->aborted = 1;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"proxy: %s: pre_connection setup failed (%d)",
proxy_function, rc);
return rc;
}
apr_socket_timeout_set(conn->sock, current_timeout);
return OK;
}
int ap_proxy_lb_workers(void)
{
/*
* Since we can't resize the scoreboard when reconfiguring, we
* have to impose a limit on the number of workers, we are
* able to reconfigure to.
*/
if (!lb_workers_limit)
lb_workers_limit = proxy_lb_workers + PROXY_DYNAMIC_BALANCER_LIMIT;
return lb_workers_limit;
}
PROXY_DECLARE(void) ap_proxy_backend_broke(request_rec *r,
apr_bucket_brigade *brigade)
{
apr_bucket *e;
conn_rec *c = r->connection;
r->no_cache = 1;
/*
* If this is a subrequest, then prevent also caching of the main
* request.
*/
if (r->main)
r->main->no_cache = 1;
e = ap_bucket_error_create(HTTP_BAD_GATEWAY, NULL, c->pool,
c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(brigade, e);
e = apr_bucket_eos_create(c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(brigade, e);
}
/*
* 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.
*/
PROXY_DECLARE(apr_status_t)
ap_proxy_buckets_lifetime_transform(request_rec *r, apr_bucket_brigade *from,
apr_bucket_brigade *to)
{
apr_bucket *e;
apr_bucket *new;
const char *data;
apr_size_t bytes;
apr_status_t rv = APR_SUCCESS;
apr_brigade_cleanup(to);
for (e = APR_BRIGADE_FIRST(from);
e != APR_BRIGADE_SENTINEL(from);
e = APR_BUCKET_NEXT(e)) {
if (!APR_BUCKET_IS_METADATA(e)) {
apr_bucket_read(e, &data, &bytes, APR_BLOCK_READ);
new = apr_bucket_transient_create(data, bytes, r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(to, new);
}
else if (APR_BUCKET_IS_FLUSH(e)) {
new = apr_bucket_flush_create(r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(to, new);
}
else if (APR_BUCKET_IS_EOS(e)) {
new = apr_bucket_eos_create(r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(to, new);
}
else {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"proxy: Unhandled bucket type of type %s in"
" ap_proxy_buckets_lifetime_transform", e->type->name);
rv = APR_EGENERAL;
}
}
return rv;
}