proxy_util.c revision 19bb1e938b464a3e961f346e9e1ed8ffa85d55b5
ee649f9236fe7fcf255bbfa11f2cce080f996521sf/* Copyright 1999-2004 The Apache Software Foundation
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * Licensed under the Apache License, Version 2.0 (the "License");
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * you may not use this file except in compliance with the License.
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * You may obtain a copy of the License at
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * Unless required by applicable law or agreed to in writing, software
96ad5d81ee4a2cc66a4ae19893efc8aa6d06fae7jailletc * distributed under the License is distributed on an "AS IS" BASIS,
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * See the License for the specific language governing permissions and
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * limitations under the License.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen/* Utility routines for Apache proxy */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf/* Global balancer counter */
5d01f40ffd657dd2ac567aacd93cabd162ddfa79coarstatic int lb_workers = 0;
5d01f40ffd657dd2ac567aacd93cabd162ddfa79coarstatic int lb_workers_limit = 0;
ee649f9236fe7fcf255bbfa11f2cce080f996521sfstatic int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r);
ee649f9236fe7fcf255bbfa11f2cce080f996521sfstatic int proxy_match_domainname(struct dirconn_entry *This, request_rec *r);
ee649f9236fe7fcf255bbfa11f2cce080f996521sfstatic int proxy_match_hostname(struct dirconn_entry *This, request_rec *r);
ee649f9236fe7fcf255bbfa11f2cce080f996521sfstatic int proxy_match_word(struct dirconn_entry *This, request_rec *r);
ee649f9236fe7fcf255bbfa11f2cce080f996521sfAPR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, create_req,
ee649f9236fe7fcf255bbfa11f2cce080f996521sf/* already called in the knowledge that the characters are hex digits */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf#else /*APR_CHARSET_EBCDIC*/
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* we assume that the hex value refers to an ASCII character
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * so convert to EBCDIC so that it makes sense locally;
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * example:
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * client specifies %20 in URL to refer to a space char;
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * at this point we're called with EBCDIC "20"; after turning
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * EBCDIC "20" into binary 0x20, we then need to assume that 0x20
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * represents an ASCII char and convert 0x20 to EBCDIC, yielding
ee649f9236fe7fcf255bbfa11f2cce080f996521sf return buf[0];
ee649f9236fe7fcf255bbfa11f2cce080f996521sf#endif /*APR_CHARSET_EBCDIC*/
ee649f9236fe7fcf255bbfa11f2cce080f996521sf x[0] = '%';
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (i >= 10)
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (i >= 10)
ee649f9236fe7fcf255bbfa11f2cce080f996521sf#else /*APR_CHARSET_EBCDIC*/
ee649f9236fe7fcf255bbfa11f2cce080f996521sf x[0] = '%';
ee649f9236fe7fcf255bbfa11f2cce080f996521sf#endif /*APR_CHARSET_EBCDIC*/
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * canonicalise a URL-encoded string
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * Convert a URL-encoded string to canonical form.
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * It decodes characters which need not be encoded,
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * and encodes those which must be encoded, and does not touch
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * those which must not be touched.
ee649f9236fe7fcf255bbfa11f2cce080f996521sfPROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, enum enctype t,
ee649f9236fe7fcf255bbfa11f2cce080f996521sf int i, j, ch;
ee649f9236fe7fcf255bbfa11f2cce080f996521sf char *allowed; /* characters which should not be encoded */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf char *reserved; /* characters which much not be en/de-coded */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf/* N.B. in addition to :@&=, this allows ';' in an http path
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * and '?' in an ftp path -- this may be revised
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * Also, it makes a '+' character in a search string reserved, as
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * it may be form-encoded. (Although RFC 1738 doesn't allow this -
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * it only permits ; / ? : @ = & as reserved chars.)
ee649f9236fe7fcf255bbfa11f2cce080f996521sf else if (t == enc_search)
ee649f9236fe7fcf255bbfa11f2cce080f996521sf else if (t == enc_user)
ee649f9236fe7fcf255bbfa11f2cce080f996521sf else if (t == enc_fpath)
ee649f9236fe7fcf255bbfa11f2cce080f996521sf else /* if (t == enc_parm) */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf else if (t == enc_search)
ee649f9236fe7fcf255bbfa11f2cce080f996521sf for (i = 0, j = 0; i < len; i++, j++) {
ee649f9236fe7fcf255bbfa11f2cce080f996521sf/* always handle '/' first */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf/* decode it if not already done */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (ch != 0 && strchr(reserved, ch)) { /* keep it encoded */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf/* recode it, if necessary */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf y[j] = '\0';
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * Parses network-location.
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * urlp on input the URL; on output the path, after the leading /
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * user NULL if no user/password permitted
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * password holder for password
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * host holder for host
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * port port number; only set if one is supplied.
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * Returns an error string.
ee649f9236fe7fcf255bbfa11f2cce080f996521sf ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp,
ee649f9236fe7fcf255bbfa11f2cce080f996521sf return "Malformed URL";
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* find _last_ '@' since it might occur in user/password part */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf/* find password */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf password = ap_proxy_canonenc(p, strp + 1, strlen(strp + 1), enc_user, 1);
ee649f9236fe7fcf255bbfa11f2cce080f996521sf return "Bad %-escape in URL (password)";
ee649f9236fe7fcf255bbfa11f2cce080f996521sf user = ap_proxy_canonenc(p, user, strlen(user), enc_user, 1);
ee649f9236fe7fcf255bbfa11f2cce080f996521sf return "Bad %-escape in URL (username)";
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* Parse the host string to separate host portion from optional port.
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * Perform range checking on port.
ee649f9236fe7fcf255bbfa11f2cce080f996521sf rv = apr_parse_addr_port(&addr, &scope_id, &tmp_port, host, p);
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (rv != APR_SUCCESS || addr == NULL || scope_id != NULL) {
ee649f9236fe7fcf255bbfa11f2cce080f996521sf return "Invalid host/port";
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (tmp_port != 0) { /* only update caller's port if port was specified */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf ap_str_tolower(addr); /* DNS names are case-insensitive */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * If the date is a valid RFC 850 date or asctime() date, then it
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * is converted to the RFC 1123 format, otherwise it is not modified.
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * This routine is not very fast at doing conversions, as it uses
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * sscanf and sprintf. However, if the date is already correctly
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * formatted, then it exits very quickly.
ee649f9236fe7fcf255bbfa11f2cce080f996521sfPROXY_DECLARE(const char *)
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* check for RFC 850 date */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf *q = '\0';
ee649f9236fe7fcf255bbfa11f2cce080f996521sf return x; /* not a valid date */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (q[4] != '-' || q[8] != '-' || q[11] != ' ' || q[14] != ':' ||
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (sscanf(q + 2, "%u-%3s-%u %u:%u:%u %3s", &mday, month, &year,
ee649f9236fe7fcf255bbfa11f2cce080f996521sf/* check for acstime() date */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (x[3] != ' ' || x[7] != ' ' || x[10] != ' ' || x[13] != ':' ||
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (sscanf(x, "%3s %3s %u %u:%u:%u %u", week, month, &mday, &hour,
ee649f9236fe7fcf255bbfa11f2cce080f996521sf/* check date */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf apr_snprintf(q, 30, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", apr_day_snames[wk],
ee649f9236fe7fcf255bbfa11f2cce080f996521sfPROXY_DECLARE(request_rec *)ap_proxy_make_fake_req(conn_rec *c, request_rec *r)
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * list is a comma-separated list of case-insensitive tokens, with
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * optional whitespace around the tokens.
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * The return returns 1 if the token val is found in the list, or 0
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * otherwise.
ee649f9236fe7fcf255bbfa11f2cce080f996521sfPROXY_DECLARE(int) ap_proxy_liststr(const char *list, const char *val)
ee649f9236fe7fcf255bbfa11f2cce080f996521sf const char *p;
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (p != NULL) {
ee649f9236fe7fcf255bbfa11f2cce080f996521sf while (apr_isspace(*p));
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * list is a comma-separated list of case-insensitive tokens, with
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * optional whitespace around the tokens.
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * if val appears on the list of tokens, it is removed from the list,
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * and the new list is returned.
ee649f9236fe7fcf255bbfa11f2cce080f996521sfPROXY_DECLARE(char *)ap_proxy_removestr(apr_pool_t *pool, const char *list, const char *val)
ee649f9236fe7fcf255bbfa11f2cce080f996521sf const char *p;
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (p != NULL) {
ee649f9236fe7fcf255bbfa11f2cce080f996521sf while (apr_isspace(*p));
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* do nothing */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf new = apr_pstrcat(pool, new, ",", apr_pstrndup(pool, list, i), NULL);
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * Converts 8 hex digits to a time integer
ee649f9236fe7fcf255bbfa11f2cce080f996521sf unsigned int j;
ee649f9236fe7fcf255bbfa11f2cce080f996521sf for (i = 0, j = 0; i < 8; i++) {
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (j == 0xffffffff)
ee649f9236fe7fcf255bbfa11f2cce080f996521sf * Converts a time integer to 8 hex digits
ee649f9236fe7fcf255bbfa11f2cce080f996521sf unsigned int j = t;
ee649f9236fe7fcf255bbfa11f2cce080f996521sf for (i = 7; i >= 0; i--) {
ee649f9236fe7fcf255bbfa11f2cce080f996521sfPROXY_DECLARE(int) ap_proxyerror(request_rec *r, int statuscode, const char *message)
ee649f9236fe7fcf255bbfa11f2cce080f996521sf "The proxy server could not handle the request "
ee649f9236fe7fcf255bbfa11f2cce080f996521sf "Reason: <strong>",
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* Allow "error-notes" string to be printed by ap_send_error_response() */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf apr_table_setn(r->notes, "verbose-error-to", apr_pstrdup(r->pool, "*"));
ee649f9236fe7fcf255bbfa11f2cce080f996521sf r->status_line = apr_psprintf(r->pool, "%3.3u Proxy Error", statuscode);
ee649f9236fe7fcf255bbfa11f2cce080f996521sfstatic const char *
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* Set url to the first char after "scheme://" */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf url = apr_pstrdup(r->pool, &url[1]); /* make it point to "//", which is what proxy_canon_netloc expects */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf err = ap_proxy_canon_netloc(r->pool, &url, &user, &password, &host, &port);
ee649f9236fe7fcf255bbfa11f2cce080f996521sf/* Return TRUE if addr represents an IP address (or an IP network address) */
ee649f9236fe7fcf255bbfa11f2cce080f996521sfPROXY_DECLARE(int) ap_proxy_is_ipaddr(struct dirconn_entry *This, apr_pool_t *p)
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* if the address is given with an explicit netmask, use that */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* Due to a deficiency in apr_inet_addr(), it is impossible to parse */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* "partial" addresses (with less than 4 quads) correctly, i.e. */
4aa603e6448b99f9371397d439795c91a93637eand /* 192.168.123 is parsed as 192.168.0.123, which is not what I want. */
4aa603e6448b99f9371397d439795c91a93637eand /* I therefore have to parse the IP address manually: */
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh /*if (proxy_readmask(This->name, &This->addr.s_addr, &This->mask.s_addr) == 0) */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* addr and mask were set by proxy_readmask() */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /*return 1; */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* Parse IP addr manually, optionally allowing */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* abbreviated net addresses like 192.168. */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* Iterate over up to 4 (dotted) quads. */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (*addr == '/' && quads > 0) /* netmask starts here. */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf return 0; /* no digit at start of quad */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (tmp == addr) /* expected a digit, found something else */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* invalid octet */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (addr[0] == '/' && apr_isdigit(addr[1])) { /* net mask follows: */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (tmp == addr) /* expected a digit, found something else */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (bits < 0 || bits > 32) /* netmask must be between 0 and 32 */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* Determine (i.e., "guess") netmask by counting the */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* number of trailing .0's; reduce #quads appropriately */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* (so that 192.168.0.0 is equivalent to 192.168.) */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* "IP Address should be given in dotted-quad form, optionally followed by a netmask (e.g., 192.168.111.0/24)"; */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* every zero-byte counts as 8 zero-bits */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (bits != 32) /* no warning for fully qualified IP address */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf "Warning: NetMask not supplied with IP-Addr; guessing: %s/%ld\n",
ee649f9236fe7fcf255bbfa11f2cce080f996521sf This->mask.s_addr = htonl(APR_INADDR_NONE << (32 - bits));
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (*addr == '\0' && (This->addr.s_addr & ~This->mask.s_addr) != 0) {
ee649f9236fe7fcf255bbfa11f2cce080f996521sf "Warning: NetMask and IP-Addr disagree in %s/%ld\n",
ee649f9236fe7fcf255bbfa11f2cce080f996521sf " Set to %s/%ld\n",
ee649f9236fe7fcf255bbfa11f2cce080f996521sf return (*addr == '\0'); /* okay iff we've parsed the whole string */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf/* Return TRUE if addr represents an IP address (or an IP network address) */
ee649f9236fe7fcf255bbfa11f2cce080f996521sfstatic int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r)
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (4 == sscanf(host, "%d.%d.%d.%d", &ip_addr[0], &ip_addr[1], &ip_addr[2], &ip_addr[3])) {
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (This->addr.s_addr == (addr.s_addr & This->mask.s_addr)) {
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (apr_sockaddr_info_get(&reqaddr, host, APR_UNSPEC, 0, 0, r->pool)
ee649f9236fe7fcf255bbfa11f2cce080f996521sf "2)IP-NoMatch: hostname=%s msg=Host not found",
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* Try to deal with multiple IP addr's for a host */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf /* FIXME: This needs to be able to deal with IPv6 */
ee649f9236fe7fcf255bbfa11f2cce080f996521sf if (This->addr.s_addr == (ip->s_addr & This->mask.s_addr)) {
0d0ba3a410038e179b695446bb149cce6264e0abnd/* Return TRUE if addr represents a domain name */
0d0ba3a410038e179b695446bb149cce6264e0abndPROXY_DECLARE(int) ap_proxy_is_domainname(struct dirconn_entry *This, apr_pool_t *p)
727872d18412fc021f03969b8641810d8896820bhumbedooh /* Domain name must start with a '.' */
205f749042ed530040a4f0080dbcb47ceae8a374rjung /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen for (i = 0; apr_isalnum(addr[i]) || addr[i] == '-' || addr[i] == '.'; ++i)
--d_len;
--h_len;
int h2_len;
int h1_len;
while (addr) {
--h2_len;
--h1_len;
return HTTP_FORBIDDEN;
while (conf_addr) {
while (uri_addr) {
char *conf_ip;
char *uri_ip;
return HTTP_FORBIDDEN;
return OK;
return OK;
* ap_rgetline() in protocol.c. Deprecate this function and use ap_rgetline()
apr_bucket *e;
char *response;
int found = 0;
buff[0] = 0;
*eos = 0;
while (!found) {
return rv;
while (!found) {
return APR_ECONNABORTED;
if (APR_BUCKET_IS_EOS(e)) {
return rv;
if (len > 0) {
return APR_SUCCESS;
if (!initial) {
count++;
const char *url)
return NULL;
return balancer;
balancer++;
return NULL;
apr_pool_t *p,
const char *url)
#if APR_HAS_THREADS
return NULL;
const char *url)
return NULL;
return worker;
worker++;
return NULL;
return APR_SUCCESS;
apr_pool_t *p,
const char *url)
int port;
if (q != NULL) {
return NULL;
PROXY_DECLARE(void)
int mpm_daemons;
++lb_workers;
request_rec *r,
int access_status;
if (*worker) {
return access_status;
request_rec *r,
int access_status;
if (balancer)
return access_status;
const char *proxy_function,
const char *backend_name,
server_rec *s,
apr_pool_t *p)
int connected = 0;
int loglevel;
return APR_SUCCESS;
#if APR_HAS_THREADS
return APR_SUCCESS;
return APR_SUCCESS;
if (s != NULL)
return APR_SUCCESS;
#if APR_HAS_THREADS
int mpm_threads;
#if (APR_MAJOR_VERSION > 0)
return rv;
server_rec *s)
return OK;
return DECLINED;
return OK;
server_rec *s)
return HTTP_INTERNAL_SERVER_ERROR;
return HTTP_SERVICE_UNAVAILABLE;
#if APR_HAS_THREADS
return HTTP_SERVICE_UNAVAILABLE;
return OK;
server_rec *s)
return OK;
PROXY_DECLARE(int)
char **url,
const char *proxyname,
char *server_portstr,
int server_portstr_size)
int server_port;
NULL));
if (proxyname) {
return OK;
server_rec *s)
int connected = 0;
int loglevel;
conn_rec *c,
server_rec *s)
c->bucket_alloc);
return HTTP_INTERNAL_SERVER_ERROR;
return HTTP_INTERNAL_SERVER_ERROR;
return OK;
return lb_workers_limit;