2006-06-25 20:48:02 -04:00
|
|
|
/*
|
|
|
|
|
* Proxy variables and functions.
|
|
|
|
|
*
|
2009-03-05 17:48:25 -05:00
|
|
|
* Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
|
2006-06-25 20:48:02 -04:00
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
|
* as published by the Free Software Foundation; either version
|
|
|
|
|
* 2 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <unistd.h>
|
2007-11-30 12:38:35 -05:00
|
|
|
#include <string.h>
|
2006-06-25 20:48:02 -04:00
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
2006-06-29 11:53:05 -04:00
|
|
|
#include <common/defaults.h>
|
2008-07-09 14:34:27 -04:00
|
|
|
#include <common/cfgparse.h>
|
2006-06-29 11:53:05 -04:00
|
|
|
#include <common/compat.h>
|
2006-06-29 12:54:54 -04:00
|
|
|
#include <common/config.h>
|
2007-10-28 06:14:07 -04:00
|
|
|
#include <common/errors.h>
|
2007-05-13 18:39:29 -04:00
|
|
|
#include <common/memory.h>
|
2006-06-29 11:53:05 -04:00
|
|
|
#include <common/time.h>
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2014-03-15 02:43:51 -04:00
|
|
|
#include <eb32tree.h>
|
|
|
|
|
#include <ebistree.h>
|
|
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
#include <types/global.h>
|
2012-11-11 18:42:33 -05:00
|
|
|
#include <types/obj_type.h>
|
2010-09-23 12:44:36 -04:00
|
|
|
#include <types/peers.h>
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2007-10-11 14:48:58 -04:00
|
|
|
#include <proto/backend.h>
|
2006-06-25 20:48:02 -04:00
|
|
|
#include <proto/fd.h>
|
2009-07-12 03:47:04 -04:00
|
|
|
#include <proto/hdr_idx.h>
|
2012-09-12 16:58:11 -04:00
|
|
|
#include <proto/listener.h>
|
2006-06-25 20:48:02 -04:00
|
|
|
#include <proto/log.h>
|
2007-10-28 20:09:36 -04:00
|
|
|
#include <proto/proto_tcp.h>
|
2010-05-31 11:01:36 -04:00
|
|
|
#include <proto/proto_http.h>
|
2006-06-25 20:48:02 -04:00
|
|
|
#include <proto/proxy.h>
|
2010-08-27 12:26:11 -04:00
|
|
|
#include <proto/signal.h>
|
2010-09-23 12:44:36 -04:00
|
|
|
#include <proto/task.h>
|
2006-06-25 20:48:02 -04:00
|
|
|
|
|
|
|
|
|
2011-07-25 10:33:49 -04:00
|
|
|
int listeners; /* # of proxy listeners, set by cfgparse */
|
2006-06-25 20:48:02 -04:00
|
|
|
struct proxy *proxy = NULL; /* list of all existing proxies */
|
2009-10-04 17:04:08 -04:00
|
|
|
struct eb_root used_proxy_id = EB_ROOT; /* list of proxy IDs in use */
|
2014-03-15 02:22:35 -04:00
|
|
|
struct eb_root proxy_by_name = EB_ROOT; /* tree of proxies sorted by name */
|
2010-12-12 08:00:34 -05:00
|
|
|
unsigned int error_snapshot_id = 0; /* global ID assigned to each error then incremented */
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2006-12-29 08:19:17 -05:00
|
|
|
/*
|
2007-11-04 01:04:43 -05:00
|
|
|
* This function returns a string containing a name describing capabilities to
|
|
|
|
|
* report comprehensible error messages. Specifically, it will return the words
|
|
|
|
|
* "frontend", "backend", "ruleset" when appropriate, or "proxy" for all other
|
|
|
|
|
* cases including the proxies declared in "listen" mode.
|
2006-12-29 08:19:17 -05:00
|
|
|
*/
|
2007-11-04 01:04:43 -05:00
|
|
|
const char *proxy_cap_str(int cap)
|
2006-12-29 08:19:17 -05:00
|
|
|
{
|
2007-11-04 01:04:43 -05:00
|
|
|
if ((cap & PR_CAP_LISTEN) != PR_CAP_LISTEN) {
|
|
|
|
|
if (cap & PR_CAP_FE)
|
|
|
|
|
return "frontend";
|
|
|
|
|
else if (cap & PR_CAP_BE)
|
|
|
|
|
return "backend";
|
|
|
|
|
else if (cap & PR_CAP_RS)
|
|
|
|
|
return "ruleset";
|
|
|
|
|
}
|
|
|
|
|
return "proxy";
|
2006-12-29 08:19:17 -05:00
|
|
|
}
|
|
|
|
|
|
2007-11-03 18:41:58 -04:00
|
|
|
/*
|
|
|
|
|
* This function returns a string containing the mode of the proxy in a format
|
|
|
|
|
* suitable for error messages.
|
|
|
|
|
*/
|
|
|
|
|
const char *proxy_mode_str(int mode) {
|
|
|
|
|
|
|
|
|
|
if (mode == PR_MODE_TCP)
|
|
|
|
|
return "tcp";
|
|
|
|
|
else if (mode == PR_MODE_HTTP)
|
|
|
|
|
return "http";
|
|
|
|
|
else if (mode == PR_MODE_HEALTH)
|
|
|
|
|
return "health";
|
|
|
|
|
else
|
|
|
|
|
return "unknown";
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-10 12:35:51 -04:00
|
|
|
/*
|
|
|
|
|
* This function scans the list of backends and servers to retrieve the first
|
|
|
|
|
* backend and the first server with the given names, and sets them in both
|
|
|
|
|
* parameters. It returns zero if either is not found, or non-zero and sets
|
|
|
|
|
* the ones it did not found to NULL. If a NULL pointer is passed for the
|
|
|
|
|
* backend, only the pointer to the server will be updated.
|
|
|
|
|
*/
|
|
|
|
|
int get_backend_server(const char *bk_name, const char *sv_name,
|
|
|
|
|
struct proxy **bk, struct server **sv)
|
|
|
|
|
{
|
|
|
|
|
struct proxy *p;
|
|
|
|
|
struct server *s;
|
2014-03-15 02:57:11 -04:00
|
|
|
int sid;
|
2009-10-10 12:35:51 -04:00
|
|
|
|
|
|
|
|
*sv = NULL;
|
|
|
|
|
|
2012-10-04 02:47:34 -04:00
|
|
|
sid = -1;
|
2009-10-10 16:33:08 -04:00
|
|
|
if (*sv_name == '#')
|
|
|
|
|
sid = atoi(sv_name + 1);
|
|
|
|
|
|
2014-03-15 02:57:11 -04:00
|
|
|
p = findproxy(bk_name, PR_CAP_BE);
|
2009-10-10 12:35:51 -04:00
|
|
|
if (bk)
|
|
|
|
|
*bk = p;
|
|
|
|
|
if (!p)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
for (s = p->srv; s; s = s->next)
|
2012-11-14 18:15:18 -05:00
|
|
|
if ((sid >= 0 && s->puid == sid) ||
|
|
|
|
|
(sid < 0 && strcmp(s->id, sv_name) == 0))
|
2009-10-10 12:35:51 -04:00
|
|
|
break;
|
|
|
|
|
*sv = s;
|
|
|
|
|
if (!s)
|
|
|
|
|
return 0;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-02 19:30:13 -05:00
|
|
|
/* This function parses a "timeout" statement in a proxy section. It returns
|
|
|
|
|
* -1 if there is any error, 1 for a warning, otherwise zero. If it does not
|
2012-05-08 13:47:01 -04:00
|
|
|
* return zero, it will write an error or warning message into a preallocated
|
|
|
|
|
* buffer returned at <err>. The trailing is not be written. The function must
|
|
|
|
|
* be called with <args> pointing to the first command line word, with <proxy>
|
|
|
|
|
* pointing to the proxy being parsed, and <defpx> to the default proxy or NULL.
|
|
|
|
|
* As a special case for compatibility with older configs, it also accepts
|
|
|
|
|
* "{cli|srv|con}timeout" in args[0].
|
2007-12-02 19:30:13 -05:00
|
|
|
*/
|
2008-07-09 14:34:27 -04:00
|
|
|
static int proxy_parse_timeout(char **args, int section, struct proxy *proxy,
|
2012-09-18 14:02:48 -04:00
|
|
|
struct proxy *defpx, const char *file, int line,
|
|
|
|
|
char **err)
|
2007-12-02 19:30:13 -05:00
|
|
|
{
|
|
|
|
|
unsigned timeout;
|
|
|
|
|
int retval, cap;
|
|
|
|
|
const char *res, *name;
|
2008-07-06 18:09:58 -04:00
|
|
|
int *tv = NULL;
|
|
|
|
|
int *td = NULL;
|
2014-04-28 16:56:38 -04:00
|
|
|
int warn = 0;
|
2007-12-02 19:30:13 -05:00
|
|
|
|
|
|
|
|
retval = 0;
|
2008-07-09 14:34:27 -04:00
|
|
|
|
|
|
|
|
/* simply skip "timeout" but remain compatible with old form */
|
|
|
|
|
if (strcmp(args[0], "timeout") == 0)
|
|
|
|
|
args++;
|
|
|
|
|
|
2007-12-02 19:30:13 -05:00
|
|
|
name = args[0];
|
2014-04-28 16:56:38 -04:00
|
|
|
if (!strcmp(args[0], "client") || (!strcmp(args[0], "clitimeout") && (warn = WARN_CLITO_DEPRECATED))) {
|
2007-12-02 19:30:13 -05:00
|
|
|
name = "client";
|
2007-12-02 19:38:36 -05:00
|
|
|
tv = &proxy->timeout.client;
|
|
|
|
|
td = &defpx->timeout.client;
|
2007-12-02 19:30:13 -05:00
|
|
|
cap = PR_CAP_FE;
|
|
|
|
|
} else if (!strcmp(args[0], "tarpit")) {
|
|
|
|
|
tv = &proxy->timeout.tarpit;
|
|
|
|
|
td = &defpx->timeout.tarpit;
|
2008-01-06 07:40:03 -05:00
|
|
|
cap = PR_CAP_FE | PR_CAP_BE;
|
2010-01-10 08:46:16 -05:00
|
|
|
} else if (!strcmp(args[0], "http-keep-alive")) {
|
|
|
|
|
tv = &proxy->timeout.httpka;
|
|
|
|
|
td = &defpx->timeout.httpka;
|
|
|
|
|
cap = PR_CAP_FE | PR_CAP_BE;
|
2008-01-06 07:24:40 -05:00
|
|
|
} else if (!strcmp(args[0], "http-request")) {
|
|
|
|
|
tv = &proxy->timeout.httpreq;
|
|
|
|
|
td = &defpx->timeout.httpreq;
|
2009-07-12 04:03:17 -04:00
|
|
|
cap = PR_CAP_FE | PR_CAP_BE;
|
2014-04-28 16:56:38 -04:00
|
|
|
} else if (!strcmp(args[0], "server") || (!strcmp(args[0], "srvtimeout") && (warn = WARN_SRVTO_DEPRECATED))) {
|
2007-12-02 19:30:13 -05:00
|
|
|
name = "server";
|
2007-12-02 19:38:36 -05:00
|
|
|
tv = &proxy->timeout.server;
|
|
|
|
|
td = &defpx->timeout.server;
|
2007-12-02 19:30:13 -05:00
|
|
|
cap = PR_CAP_BE;
|
2014-04-28 16:56:38 -04:00
|
|
|
} else if (!strcmp(args[0], "connect") || (!strcmp(args[0], "contimeout") && (warn = WARN_CONTO_DEPRECATED))) {
|
2007-12-02 19:30:13 -05:00
|
|
|
name = "connect";
|
2007-12-02 19:38:36 -05:00
|
|
|
tv = &proxy->timeout.connect;
|
|
|
|
|
td = &defpx->timeout.connect;
|
2007-12-02 19:30:13 -05:00
|
|
|
cap = PR_CAP_BE;
|
2008-01-20 19:54:06 -05:00
|
|
|
} else if (!strcmp(args[0], "check")) {
|
|
|
|
|
tv = &proxy->timeout.check;
|
|
|
|
|
td = &defpx->timeout.check;
|
|
|
|
|
cap = PR_CAP_BE;
|
2007-12-02 19:30:13 -05:00
|
|
|
} else if (!strcmp(args[0], "queue")) {
|
|
|
|
|
tv = &proxy->timeout.queue;
|
|
|
|
|
td = &defpx->timeout.queue;
|
|
|
|
|
cap = PR_CAP_BE;
|
2012-05-12 06:50:00 -04:00
|
|
|
} else if (!strcmp(args[0], "tunnel")) {
|
|
|
|
|
tv = &proxy->timeout.tunnel;
|
|
|
|
|
td = &defpx->timeout.tunnel;
|
|
|
|
|
cap = PR_CAP_BE;
|
2014-05-10 08:30:07 -04:00
|
|
|
} else if (!strcmp(args[0], "client-fin")) {
|
|
|
|
|
tv = &proxy->timeout.clientfin;
|
|
|
|
|
td = &defpx->timeout.clientfin;
|
|
|
|
|
cap = PR_CAP_FE;
|
|
|
|
|
} else if (!strcmp(args[0], "server-fin")) {
|
|
|
|
|
tv = &proxy->timeout.serverfin;
|
|
|
|
|
td = &defpx->timeout.serverfin;
|
|
|
|
|
cap = PR_CAP_BE;
|
2007-12-02 19:30:13 -05:00
|
|
|
} else {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err,
|
|
|
|
|
"'timeout' supports 'client', 'server', 'connect', 'check', "
|
2014-05-10 08:30:07 -04:00
|
|
|
"'queue', 'http-keep-alive', 'http-request', 'tunnel', 'tarpit', "
|
|
|
|
|
"'client-fin' and 'server-fin' (got '%s')",
|
2012-05-08 13:47:01 -04:00
|
|
|
args[0]);
|
2007-12-02 19:30:13 -05:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (*args[1] == 0) {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "'timeout %s' expects an integer value (in milliseconds)", name);
|
2007-12-02 19:30:13 -05:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res = parse_time_err(args[1], &timeout, TIME_UNIT_MS);
|
|
|
|
|
if (res) {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "unexpected character '%c' in 'timeout %s'", *res, name);
|
2007-12-02 19:30:13 -05:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(proxy->cap & cap)) {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "'timeout %s' will be ignored because %s '%s' has no %s capability",
|
|
|
|
|
name, proxy_type_str(proxy), proxy->id,
|
|
|
|
|
(cap & PR_CAP_BE) ? "backend" : "frontend");
|
2007-12-02 19:30:13 -05:00
|
|
|
retval = 1;
|
|
|
|
|
}
|
2008-07-06 18:09:58 -04:00
|
|
|
else if (defpx && *tv != *td) {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "overwriting 'timeout %s' which was already specified", name);
|
2007-12-02 19:30:13 -05:00
|
|
|
retval = 1;
|
|
|
|
|
}
|
2014-04-28 16:56:38 -04:00
|
|
|
else if (warn) {
|
|
|
|
|
if (!already_warned(warn)) {
|
|
|
|
|
memprintf(err, "the '%s' directive is now deprecated in favor of 'timeout %s', and will not be supported in future versions.",
|
|
|
|
|
args[0], name);
|
|
|
|
|
retval = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-12-02 19:30:13 -05:00
|
|
|
|
2014-05-22 02:24:46 -04:00
|
|
|
if (*args[2] != 0) {
|
|
|
|
|
memprintf(err, "'timeout %s' : unexpected extra argument '%s' after value '%s'.", name, args[2], args[1]);
|
|
|
|
|
retval = -1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-06 18:09:58 -04:00
|
|
|
*tv = MS_TO_TICKS(timeout);
|
2007-12-02 19:30:13 -05:00
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-05 17:48:25 -05:00
|
|
|
/* This function parses a "rate-limit" statement in a proxy section. It returns
|
|
|
|
|
* -1 if there is any error, 1 for a warning, otherwise zero. If it does not
|
2012-05-08 13:47:01 -04:00
|
|
|
* return zero, it will write an error or warning message into a preallocated
|
|
|
|
|
* buffer returned at <err>. The function must be called with <args> pointing
|
|
|
|
|
* to the first command line word, with <proxy> pointing to the proxy being
|
|
|
|
|
* parsed, and <defpx> to the default proxy or NULL.
|
2009-03-05 17:48:25 -05:00
|
|
|
*/
|
|
|
|
|
static int proxy_parse_rate_limit(char **args, int section, struct proxy *proxy,
|
2012-09-18 14:02:48 -04:00
|
|
|
struct proxy *defpx, const char *file, int line,
|
|
|
|
|
char **err)
|
2009-03-05 17:48:25 -05:00
|
|
|
{
|
|
|
|
|
int retval, cap;
|
2012-05-08 13:47:01 -04:00
|
|
|
char *res;
|
2009-03-05 17:48:25 -05:00
|
|
|
unsigned int *tv = NULL;
|
|
|
|
|
unsigned int *td = NULL;
|
|
|
|
|
unsigned int val;
|
|
|
|
|
|
|
|
|
|
retval = 0;
|
|
|
|
|
|
2012-05-08 13:47:01 -04:00
|
|
|
if (strcmp(args[1], "sessions") == 0) {
|
2009-05-10 12:52:49 -04:00
|
|
|
tv = &proxy->fe_sps_lim;
|
|
|
|
|
td = &defpx->fe_sps_lim;
|
2009-03-05 17:48:25 -05:00
|
|
|
cap = PR_CAP_FE;
|
2012-05-08 13:47:01 -04:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
memprintf(err, "'%s' only supports 'sessions' (got '%s')", args[0], args[1]);
|
2009-03-05 17:48:25 -05:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-08 13:47:01 -04:00
|
|
|
if (*args[2] == 0) {
|
|
|
|
|
memprintf(err, "'%s %s' expects expects an integer value (in sessions/second)", args[0], args[1]);
|
2009-03-05 17:48:25 -05:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-08 13:47:01 -04:00
|
|
|
val = strtoul(args[2], &res, 0);
|
2009-03-05 17:48:25 -05:00
|
|
|
if (*res) {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "'%s %s' : unexpected character '%c' in integer value '%s'", args[0], args[1], *res, args[2]);
|
2009-03-05 17:48:25 -05:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(proxy->cap & cap)) {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "%s %s will be ignored because %s '%s' has no %s capability",
|
|
|
|
|
args[0], args[1], proxy_type_str(proxy), proxy->id,
|
2009-03-05 17:48:25 -05:00
|
|
|
(cap & PR_CAP_BE) ? "backend" : "frontend");
|
|
|
|
|
retval = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (defpx && *tv != *td) {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "overwriting %s %s which was already specified", args[0], args[1]);
|
2009-03-05 17:48:25 -05:00
|
|
|
retval = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*tv = val;
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-25 07:58:37 -04:00
|
|
|
/* This function parses a "max-keep-alive-queue" statement in a proxy section.
|
|
|
|
|
* It returns -1 if there is any error, 1 for a warning, otherwise zero. If it
|
|
|
|
|
* does not return zero, it will write an error or warning message into a
|
|
|
|
|
* preallocated buffer returned at <err>. The function must be called with
|
|
|
|
|
* <args> pointing to the first command line word, with <proxy> pointing to
|
|
|
|
|
* the proxy being parsed, and <defpx> to the default proxy or NULL.
|
|
|
|
|
*/
|
|
|
|
|
static int proxy_parse_max_ka_queue(char **args, int section, struct proxy *proxy,
|
|
|
|
|
struct proxy *defpx, const char *file, int line,
|
|
|
|
|
char **err)
|
|
|
|
|
{
|
|
|
|
|
int retval;
|
|
|
|
|
char *res;
|
|
|
|
|
unsigned int val;
|
|
|
|
|
|
|
|
|
|
retval = 0;
|
|
|
|
|
|
|
|
|
|
if (*args[1] == 0) {
|
|
|
|
|
memprintf(err, "'%s' expects expects an integer value (or -1 to disable)", args[0]);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val = strtol(args[1], &res, 0);
|
|
|
|
|
if (*res) {
|
|
|
|
|
memprintf(err, "'%s' : unexpected character '%c' in integer value '%s'", args[0], *res, args[1]);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(proxy->cap & PR_CAP_BE)) {
|
|
|
|
|
memprintf(err, "%s will be ignored because %s '%s' has no backend capability",
|
|
|
|
|
args[0], proxy_type_str(proxy), proxy->id);
|
|
|
|
|
retval = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* we store <val+1> so that a user-facing value of -1 is stored as zero (default) */
|
|
|
|
|
proxy->max_ka_queue = val + 1;
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-15 02:22:35 -04:00
|
|
|
/* This function inserts proxy <px> into the tree of known proxies. The proxy's
|
|
|
|
|
* name is used as the storing key so it must already have been initialized.
|
|
|
|
|
*/
|
|
|
|
|
void proxy_store_name(struct proxy *px)
|
|
|
|
|
{
|
|
|
|
|
px->conf.by_name.key = px->id;
|
|
|
|
|
ebis_insert(&proxy_by_name, &px->conf.by_name);
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-03 18:41:58 -04:00
|
|
|
/*
|
|
|
|
|
* This function finds a proxy with matching name, mode and with satisfying
|
|
|
|
|
* capabilities. It also checks if there are more matching proxies with
|
|
|
|
|
* requested name as this often leads into unexpected situations.
|
|
|
|
|
*/
|
|
|
|
|
|
2009-11-01 21:27:13 -05:00
|
|
|
struct proxy *findproxy_mode(const char *name, int mode, int cap) {
|
2007-11-03 18:41:58 -04:00
|
|
|
|
2008-02-17 19:26:35 -05:00
|
|
|
struct proxy *curproxy, *target = NULL;
|
2014-03-15 02:22:35 -04:00
|
|
|
struct ebpt_node *node;
|
|
|
|
|
|
|
|
|
|
for (node = ebis_lookup(&proxy_by_name, name); node; node = ebpt_next(node)) {
|
|
|
|
|
curproxy = container_of(node, struct proxy, conf.by_name);
|
|
|
|
|
|
|
|
|
|
if (strcmp(curproxy->id, name) != 0)
|
|
|
|
|
break;
|
2007-11-03 18:41:58 -04:00
|
|
|
|
2014-03-15 02:22:35 -04:00
|
|
|
if ((curproxy->cap & cap) != cap)
|
2007-11-03 18:41:58 -04:00
|
|
|
continue;
|
|
|
|
|
|
2009-07-12 03:47:04 -04:00
|
|
|
if (curproxy->mode != mode &&
|
|
|
|
|
!(curproxy->mode == PR_MODE_HTTP && mode == PR_MODE_TCP)) {
|
2007-11-03 18:41:58 -04:00
|
|
|
Alert("Unable to use proxy '%s' with wrong mode, required: %s, has: %s.\n",
|
|
|
|
|
name, proxy_mode_str(mode), proxy_mode_str(curproxy->mode));
|
|
|
|
|
Alert("You may want to use 'mode %s'.\n", proxy_mode_str(mode));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!target) {
|
|
|
|
|
target = curproxy;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-04 01:04:43 -05:00
|
|
|
Alert("Refusing to use duplicated proxy '%s' with overlapping capabilities: %s/%s!\n",
|
2007-11-03 18:41:58 -04:00
|
|
|
name, proxy_type_str(curproxy), proxy_type_str(target));
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return target;
|
|
|
|
|
}
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2011-08-02 05:25:54 -04:00
|
|
|
/* Returns a pointer to the proxy matching either name <name>, or id <name> if
|
|
|
|
|
* <name> begins with a '#'. NULL is returned if no match is found, as well as
|
|
|
|
|
* if multiple matches are found (eg: too large capabilities mask).
|
|
|
|
|
*/
|
2009-11-01 21:27:13 -05:00
|
|
|
struct proxy *findproxy(const char *name, int cap) {
|
|
|
|
|
|
|
|
|
|
struct proxy *curproxy, *target = NULL;
|
2012-10-04 02:47:34 -04:00
|
|
|
int pid = -1;
|
2011-08-02 05:25:54 -04:00
|
|
|
|
2014-03-15 02:43:51 -04:00
|
|
|
if (*name == '#') {
|
|
|
|
|
struct eb32_node *node;
|
|
|
|
|
|
2011-08-02 05:25:54 -04:00
|
|
|
pid = atoi(name + 1);
|
2009-11-01 21:27:13 -05:00
|
|
|
|
2014-03-15 02:43:51 -04:00
|
|
|
for (node = eb32_lookup(&used_proxy_id, pid); node; node = eb32_next(node)) {
|
|
|
|
|
curproxy = container_of(node, struct proxy, conf.id);
|
|
|
|
|
|
|
|
|
|
if (curproxy->uuid != pid)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if ((curproxy->cap & cap) != cap)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (target)
|
|
|
|
|
return NULL;
|
2009-11-01 21:27:13 -05:00
|
|
|
|
|
|
|
|
target = curproxy;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-03-15 02:43:51 -04:00
|
|
|
else {
|
|
|
|
|
struct ebpt_node *node;
|
|
|
|
|
|
|
|
|
|
for (node = ebis_lookup(&proxy_by_name, name); node; node = ebpt_next(node)) {
|
|
|
|
|
curproxy = container_of(node, struct proxy, conf.by_name);
|
|
|
|
|
|
|
|
|
|
if (strcmp(curproxy->id, name) != 0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if ((curproxy->cap & cap) != cap)
|
|
|
|
|
continue;
|
2009-11-01 21:27:13 -05:00
|
|
|
|
2014-03-15 02:43:51 -04:00
|
|
|
if (target)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
target = curproxy;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-11-01 21:27:13 -05:00
|
|
|
return target;
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-17 19:26:35 -05:00
|
|
|
/*
|
|
|
|
|
* This function finds a server with matching name within selected proxy.
|
|
|
|
|
* It also checks if there are more matching servers with
|
|
|
|
|
* requested name as this often leads into unexpected situations.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
struct server *findserver(const struct proxy *px, const char *name) {
|
|
|
|
|
|
|
|
|
|
struct server *cursrv, *target = NULL;
|
|
|
|
|
|
|
|
|
|
if (!px)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
for (cursrv = px->srv; cursrv; cursrv = cursrv->next) {
|
|
|
|
|
if (strcmp(cursrv->id, name))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (!target) {
|
|
|
|
|
target = cursrv;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-04 06:57:19 -04:00
|
|
|
Alert("Refusing to use duplicated server '%s' found in proxy: %s!\n",
|
2008-02-17 19:26:35 -05:00
|
|
|
name, px->id);
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return target;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-15 08:46:16 -04:00
|
|
|
/* This function checks that the designated proxy has no http directives
|
|
|
|
|
* enabled. It will output a warning if there are, and will fix some of them.
|
|
|
|
|
* It returns the number of fatal errors encountered. This should be called
|
|
|
|
|
* at the end of the configuration parsing if the proxy is not in http mode.
|
|
|
|
|
* The <file> argument is used to construct the error message.
|
|
|
|
|
*/
|
2009-06-22 09:48:36 -04:00
|
|
|
int proxy_cfg_ensure_no_http(struct proxy *curproxy)
|
2009-03-15 08:46:16 -04:00
|
|
|
{
|
|
|
|
|
if (curproxy->cookie_name != NULL) {
|
2009-06-22 09:48:36 -04:00
|
|
|
Warning("config : cookie will be ignored for %s '%s' (needs 'mode http').\n",
|
|
|
|
|
proxy_type_str(curproxy), curproxy->id);
|
2009-03-15 08:46:16 -04:00
|
|
|
}
|
|
|
|
|
if (curproxy->rsp_exp != NULL) {
|
2009-06-22 09:48:36 -04:00
|
|
|
Warning("config : server regular expressions will be ignored for %s '%s' (needs 'mode http').\n",
|
|
|
|
|
proxy_type_str(curproxy), curproxy->id);
|
2009-03-15 08:46:16 -04:00
|
|
|
}
|
|
|
|
|
if (curproxy->req_exp != NULL) {
|
2009-06-22 09:48:36 -04:00
|
|
|
Warning("config : client regular expressions will be ignored for %s '%s' (needs 'mode http').\n",
|
|
|
|
|
proxy_type_str(curproxy), curproxy->id);
|
2009-03-15 08:46:16 -04:00
|
|
|
}
|
|
|
|
|
if (curproxy->monitor_uri != NULL) {
|
2009-06-22 09:48:36 -04:00
|
|
|
Warning("config : monitor-uri will be ignored for %s '%s' (needs 'mode http').\n",
|
|
|
|
|
proxy_type_str(curproxy), curproxy->id);
|
2009-03-15 08:46:16 -04:00
|
|
|
}
|
2009-10-03 06:21:20 -04:00
|
|
|
if (curproxy->lbprm.algo & BE_LB_NEED_HTTP) {
|
2009-03-15 08:46:16 -04:00
|
|
|
curproxy->lbprm.algo &= ~BE_LB_ALGO;
|
|
|
|
|
curproxy->lbprm.algo |= BE_LB_ALGO_RR;
|
2009-06-22 09:48:36 -04:00
|
|
|
Warning("config : Layer 7 hash not possible for %s '%s' (needs 'mode http'). Falling back to round robin.\n",
|
|
|
|
|
proxy_type_str(curproxy), curproxy->id);
|
2009-03-15 08:46:16 -04:00
|
|
|
}
|
2009-11-09 15:27:51 -05:00
|
|
|
if (curproxy->to_log & (LW_REQ | LW_RESP)) {
|
|
|
|
|
curproxy->to_log &= ~(LW_REQ | LW_RESP);
|
2014-01-29 08:39:58 -05:00
|
|
|
Warning("parsing [%s:%d] : HTTP log/header format not usable with %s '%s' (needs 'mode http').\n",
|
2013-04-12 12:30:32 -04:00
|
|
|
curproxy->conf.lfs_file, curproxy->conf.lfs_line,
|
2009-11-09 15:27:51 -05:00
|
|
|
proxy_type_str(curproxy), curproxy->id);
|
|
|
|
|
}
|
2013-04-12 12:13:46 -04:00
|
|
|
if (curproxy->conf.logformat_string == default_http_log_format ||
|
|
|
|
|
curproxy->conf.logformat_string == clf_http_log_format) {
|
|
|
|
|
/* Note: we don't change the directive's file:line number */
|
|
|
|
|
curproxy->conf.logformat_string = default_tcp_log_format;
|
|
|
|
|
Warning("parsing [%s:%d] : 'option httplog' not usable with %s '%s' (needs 'mode http'). Falling back to 'option tcplog'.\n",
|
|
|
|
|
curproxy->conf.lfs_file, curproxy->conf.lfs_line,
|
2012-05-31 13:30:26 -04:00
|
|
|
proxy_type_str(curproxy), curproxy->id);
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-15 08:46:16 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-28 19:49:03 -04:00
|
|
|
/* Perform the most basic initialization of a proxy :
|
|
|
|
|
* memset(), list_init(*), reset_timeouts(*).
|
2011-09-07 12:41:08 -04:00
|
|
|
* Any new proxy or peer should be initialized via this function.
|
2011-07-28 19:49:03 -04:00
|
|
|
*/
|
|
|
|
|
void init_new_proxy(struct proxy *p)
|
|
|
|
|
{
|
|
|
|
|
memset(p, 0, sizeof(struct proxy));
|
2012-11-11 18:42:33 -05:00
|
|
|
p->obj_type = OBJ_TYPE_PROXY;
|
2011-07-28 19:49:03 -04:00
|
|
|
LIST_INIT(&p->pendconns);
|
|
|
|
|
LIST_INIT(&p->acl);
|
|
|
|
|
LIST_INIT(&p->http_req_rules);
|
2013-06-11 10:06:12 -04:00
|
|
|
LIST_INIT(&p->http_res_rules);
|
2014-04-28 16:05:31 -04:00
|
|
|
LIST_INIT(&p->block_rules);
|
2011-07-28 19:49:03 -04:00
|
|
|
LIST_INIT(&p->redirect_rules);
|
|
|
|
|
LIST_INIT(&p->mon_fail_cond);
|
|
|
|
|
LIST_INIT(&p->switching_rules);
|
2012-04-05 15:09:48 -04:00
|
|
|
LIST_INIT(&p->server_rules);
|
2011-07-28 19:49:03 -04:00
|
|
|
LIST_INIT(&p->persist_rules);
|
|
|
|
|
LIST_INIT(&p->sticking_rules);
|
|
|
|
|
LIST_INIT(&p->storersp_rules);
|
|
|
|
|
LIST_INIT(&p->tcp_req.inspect_rules);
|
|
|
|
|
LIST_INIT(&p->tcp_rep.inspect_rules);
|
|
|
|
|
LIST_INIT(&p->tcp_req.l4_rules);
|
|
|
|
|
LIST_INIT(&p->req_add);
|
|
|
|
|
LIST_INIT(&p->rsp_add);
|
|
|
|
|
LIST_INIT(&p->listener_queue);
|
2011-10-12 11:50:54 -04:00
|
|
|
LIST_INIT(&p->logsrvs);
|
2012-02-08 10:37:49 -05:00
|
|
|
LIST_INIT(&p->logformat);
|
2012-03-12 07:48:57 -04:00
|
|
|
LIST_INIT(&p->format_unique_id);
|
2012-09-13 11:54:29 -04:00
|
|
|
LIST_INIT(&p->conf.bind);
|
2012-09-20 10:48:07 -04:00
|
|
|
LIST_INIT(&p->conf.listeners);
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
LIST_INIT(&p->conf.args.list);
|
2013-10-06 17:24:13 -04:00
|
|
|
LIST_INIT(&p->tcpcheck_rules);
|
2011-07-28 19:49:03 -04:00
|
|
|
|
|
|
|
|
/* Timeouts are defined as -1 */
|
|
|
|
|
proxy_reset_timeouts(p);
|
|
|
|
|
p->tcp_rep.inspect_delay = TICK_ETERNITY;
|
2012-10-04 02:47:34 -04:00
|
|
|
|
|
|
|
|
/* initial uuid is unassigned (-1) */
|
|
|
|
|
p->uuid = -1;
|
2011-07-28 19:49:03 -04:00
|
|
|
}
|
|
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
/*
|
2007-04-09 13:29:56 -04:00
|
|
|
* This function creates all proxy sockets. It should be done very early,
|
|
|
|
|
* typically before privileges are dropped. The sockets will be registered
|
|
|
|
|
* but not added to any fd_set, in order not to loose them across the fork().
|
2011-07-25 02:11:52 -04:00
|
|
|
* The proxies also start in READY state because they all have their listeners
|
2011-07-25 01:37:28 -04:00
|
|
|
* bound.
|
2007-04-09 13:29:56 -04:00
|
|
|
*
|
|
|
|
|
* Its return value is composed from ERR_NONE, ERR_RETRYABLE and ERR_FATAL.
|
|
|
|
|
* Retryable errors will only be printed if <verbose> is not zero.
|
2006-06-25 20:48:02 -04:00
|
|
|
*/
|
|
|
|
|
int start_proxies(int verbose)
|
|
|
|
|
{
|
|
|
|
|
struct proxy *curproxy;
|
|
|
|
|
struct listener *listener;
|
2007-10-28 20:09:36 -04:00
|
|
|
int lerr, err = ERR_NONE;
|
|
|
|
|
int pxerr;
|
|
|
|
|
char msg[100];
|
2006-06-25 20:48:02 -04:00
|
|
|
|
|
|
|
|
for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
|
|
|
|
|
if (curproxy->state != PR_STNEW)
|
|
|
|
|
continue; /* already initialized */
|
|
|
|
|
|
|
|
|
|
pxerr = 0;
|
2012-09-20 10:48:07 -04:00
|
|
|
list_for_each_entry(listener, &curproxy->conf.listeners, by_fe) {
|
2007-10-28 20:09:36 -04:00
|
|
|
if (listener->state != LI_ASSIGNED)
|
|
|
|
|
continue; /* already started */
|
|
|
|
|
|
2010-10-22 10:06:11 -04:00
|
|
|
lerr = listener->proto->bind(listener, msg, sizeof(msg));
|
2007-10-28 20:09:36 -04:00
|
|
|
|
|
|
|
|
/* errors are reported if <verbose> is set or if they are fatal */
|
|
|
|
|
if (verbose || (lerr & (ERR_FATAL | ERR_ABORT))) {
|
|
|
|
|
if (lerr & ERR_ALERT)
|
|
|
|
|
Alert("Starting %s %s: %s\n",
|
|
|
|
|
proxy_type_str(curproxy), curproxy->id, msg);
|
|
|
|
|
else if (lerr & ERR_WARN)
|
|
|
|
|
Warning("Starting %s %s: %s\n",
|
|
|
|
|
proxy_type_str(curproxy), curproxy->id, msg);
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
|
2007-10-28 20:09:36 -04:00
|
|
|
err |= lerr;
|
|
|
|
|
if (lerr & (ERR_ABORT | ERR_FATAL)) {
|
2006-06-25 20:48:02 -04:00
|
|
|
pxerr |= 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2007-10-28 20:09:36 -04:00
|
|
|
else if (lerr & ERR_CODE) {
|
2006-06-25 20:48:02 -04:00
|
|
|
pxerr |= 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!pxerr) {
|
2011-07-25 02:11:52 -04:00
|
|
|
curproxy->state = PR_STREADY;
|
2006-06-25 20:48:02 -04:00
|
|
|
send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
|
|
|
|
|
}
|
2007-10-28 20:09:36 -04:00
|
|
|
|
|
|
|
|
if (err & ERR_ABORT)
|
|
|
|
|
break;
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2011-07-25 10:33:49 -04:00
|
|
|
* This is the proxy management task. It enables proxies when there are enough
|
REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-02 18:22:06 -04:00
|
|
|
* free streams, or stops them when the table is full. It is designed to be
|
2011-07-25 10:33:49 -04:00
|
|
|
* called as a task which is woken up upon stopping or when rate limiting must
|
|
|
|
|
* be enforced.
|
2006-06-25 20:48:02 -04:00
|
|
|
*/
|
2011-07-25 10:33:49 -04:00
|
|
|
struct task *manage_proxy(struct task *t)
|
2006-06-25 20:48:02 -04:00
|
|
|
{
|
2011-07-25 10:33:49 -04:00
|
|
|
struct proxy *p = t->context;
|
|
|
|
|
int next = TICK_ETERNITY;
|
2009-03-06 03:18:27 -05:00
|
|
|
unsigned int wait;
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2011-07-25 10:33:49 -04:00
|
|
|
/* We should periodically try to enable listeners waiting for a
|
|
|
|
|
* global resource here.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* first, let's check if we need to stop the proxy */
|
|
|
|
|
if (unlikely(stopping && p->state != PR_STSTOPPED)) {
|
|
|
|
|
int t;
|
|
|
|
|
t = tick_remain(now_ms, p->stop_time);
|
|
|
|
|
if (t == 0) {
|
|
|
|
|
Warning("Proxy %s stopped (FE: %lld conns, BE: %lld conns).\n",
|
|
|
|
|
p->id, p->fe_counters.cum_conn, p->be_counters.cum_conn);
|
|
|
|
|
send_log(p, LOG_WARNING, "Proxy %s stopped (FE: %lld conns, BE: %lld conns).\n",
|
|
|
|
|
p->id, p->fe_counters.cum_conn, p->be_counters.cum_conn);
|
|
|
|
|
stop_proxy(p);
|
|
|
|
|
/* try to free more memory */
|
|
|
|
|
pool_gc2();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
next = tick_first(next, p->stop_time);
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-07-25 05:54:17 -04:00
|
|
|
|
2013-09-04 11:54:01 -04:00
|
|
|
/* If the proxy holds a stick table, we need to purge all unused
|
|
|
|
|
* entries. These are all the ones in the table with ref_cnt == 0
|
|
|
|
|
* and all the ones in the pool used to allocate new entries. Any
|
REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-02 18:22:06 -04:00
|
|
|
* entry attached to an existing stream waiting for a store will
|
2013-09-04 11:54:01 -04:00
|
|
|
* be in neither list. Any entry being dumped will have ref_cnt > 0.
|
|
|
|
|
* However we protect tables that are being synced to peers.
|
|
|
|
|
*/
|
|
|
|
|
if (unlikely(stopping && p->state == PR_STSTOPPED && p->table.current)) {
|
|
|
|
|
if (!p->table.syncing) {
|
|
|
|
|
stktable_trash_oldest(&p->table, p->table.current);
|
|
|
|
|
pool_gc2();
|
|
|
|
|
}
|
|
|
|
|
if (p->table.current) {
|
|
|
|
|
/* some entries still remain, let's recheck in one second */
|
|
|
|
|
next = tick_first(next, tick_add(now_ms, 1000));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-25 10:33:49 -04:00
|
|
|
/* the rest below is just for frontends */
|
|
|
|
|
if (!(p->cap & PR_CAP_FE))
|
|
|
|
|
goto out;
|
2011-07-25 01:37:28 -04:00
|
|
|
|
2011-07-25 10:33:49 -04:00
|
|
|
/* check the various reasons we may find to block the frontend */
|
|
|
|
|
if (unlikely(p->feconn >= p->maxconn)) {
|
|
|
|
|
if (p->state == PR_STREADY)
|
|
|
|
|
p->state = PR_STFULL;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2011-07-25 01:37:28 -04:00
|
|
|
|
2011-07-25 10:33:49 -04:00
|
|
|
/* OK we have no reason to block, so let's unblock if we were blocking */
|
|
|
|
|
if (p->state == PR_STFULL)
|
|
|
|
|
p->state = PR_STREADY;
|
2009-03-05 17:48:25 -05:00
|
|
|
|
2011-07-25 10:33:49 -04:00
|
|
|
if (p->fe_sps_lim &&
|
|
|
|
|
(wait = next_event_delay(&p->fe_sess_per_sec, p->fe_sps_lim, 0))) {
|
|
|
|
|
/* we're blocking because a limit was reached on the number of
|
|
|
|
|
* requests/s on the frontend. We want to re-check ASAP, which
|
|
|
|
|
* means in 1 ms before estimated expiration date, because the
|
|
|
|
|
* timer will have settled down.
|
|
|
|
|
*/
|
|
|
|
|
next = tick_first(next, tick_add(now_ms, wait));
|
|
|
|
|
goto out;
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
2011-07-25 10:33:49 -04:00
|
|
|
|
|
|
|
|
/* The proxy is not limited so we can re-enable any waiting listener */
|
|
|
|
|
if (!LIST_ISEMPTY(&p->listener_queue))
|
|
|
|
|
dequeue_all_listeners(&p->listener_queue);
|
|
|
|
|
out:
|
|
|
|
|
t->expire = next;
|
|
|
|
|
task_queue(t);
|
|
|
|
|
return t;
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* this function disables health-check servers so that the process will quickly be ignored
|
|
|
|
|
* by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
|
|
|
|
|
* time will not be used since it would already not listen anymore to the socket.
|
|
|
|
|
*/
|
|
|
|
|
void soft_stop(void)
|
|
|
|
|
{
|
|
|
|
|
struct proxy *p;
|
2011-07-25 05:16:24 -04:00
|
|
|
struct peers *prs;
|
2006-06-25 20:48:02 -04:00
|
|
|
|
|
|
|
|
stopping = 1;
|
|
|
|
|
p = proxy;
|
2008-06-23 08:00:57 -04:00
|
|
|
tv_update_date(0,1); /* else, the old time before select will be used */
|
2006-06-25 20:48:02 -04:00
|
|
|
while (p) {
|
|
|
|
|
if (p->state != PR_STSTOPPED) {
|
2008-10-10 11:51:34 -04:00
|
|
|
Warning("Stopping %s %s in %d ms.\n", proxy_cap_str(p->cap), p->id, p->grace);
|
|
|
|
|
send_log(p, LOG_WARNING, "Stopping %s %s in %d ms.\n", proxy_cap_str(p->cap), p->id, p->grace);
|
2008-07-06 18:09:58 -04:00
|
|
|
p->stop_time = tick_add(now_ms, p->grace);
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
2010-09-23 12:44:36 -04:00
|
|
|
if (p->table.size && p->table.sync_task)
|
|
|
|
|
task_wakeup(p->table.sync_task, TASK_WOKEN_MSG);
|
|
|
|
|
|
2011-07-25 10:33:49 -04:00
|
|
|
/* wake every proxy task up so that they can handle the stopping */
|
2012-10-03 18:14:33 -04:00
|
|
|
if (p->task)
|
|
|
|
|
task_wakeup(p->task, TASK_WOKEN_MSG);
|
2006-06-25 20:48:02 -04:00
|
|
|
p = p->next;
|
|
|
|
|
}
|
2011-07-25 05:16:24 -04:00
|
|
|
|
|
|
|
|
prs = peers;
|
|
|
|
|
while (prs) {
|
|
|
|
|
stop_proxy((struct proxy *)prs->peers_fe);
|
|
|
|
|
prs = prs->next;
|
|
|
|
|
}
|
2010-08-27 12:26:11 -04:00
|
|
|
/* signal zero is used to broadcast the "stopping" event */
|
|
|
|
|
signal_handler(0);
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-07-24 12:28:10 -04:00
|
|
|
/* Temporarily disables listening on all of the proxy's listeners. Upon
|
|
|
|
|
* success, the proxy enters the PR_PAUSED state. If disabling at least one
|
|
|
|
|
* listener returns an error, then the proxy state is set to PR_STERROR
|
2011-09-07 13:14:57 -04:00
|
|
|
* because we don't know how to resume from this. The function returns 0
|
|
|
|
|
* if it fails, or non-zero on success.
|
2006-06-25 20:48:02 -04:00
|
|
|
*/
|
2011-09-07 13:14:57 -04:00
|
|
|
int pause_proxy(struct proxy *p)
|
2006-06-25 20:48:02 -04:00
|
|
|
{
|
|
|
|
|
struct listener *l;
|
2011-09-07 13:14:57 -04:00
|
|
|
|
|
|
|
|
if (!(p->cap & PR_CAP_FE) || p->state == PR_STERROR ||
|
|
|
|
|
p->state == PR_STSTOPPED || p->state == PR_STPAUSED)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
Warning("Pausing %s %s.\n", proxy_cap_str(p->cap), p->id);
|
|
|
|
|
send_log(p, LOG_WARNING, "Pausing %s %s.\n", proxy_cap_str(p->cap), p->id);
|
|
|
|
|
|
2012-09-20 10:48:07 -04:00
|
|
|
list_for_each_entry(l, &p->conf.listeners, by_fe) {
|
2011-07-24 12:28:10 -04:00
|
|
|
if (!pause_listener(l))
|
2006-06-25 20:48:02 -04:00
|
|
|
p->state = PR_STERROR;
|
|
|
|
|
}
|
2011-09-07 13:14:57 -04:00
|
|
|
|
|
|
|
|
if (p->state == PR_STERROR) {
|
|
|
|
|
Warning("%s %s failed to enter pause mode.\n", proxy_cap_str(p->cap), p->id);
|
|
|
|
|
send_log(p, LOG_WARNING, "%s %s failed to enter pause mode.\n", proxy_cap_str(p->cap), p->id);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p->state = PR_STPAUSED;
|
|
|
|
|
return 1;
|
2008-10-12 06:07:48 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This function completely stops a proxy and releases its listeners. It has
|
|
|
|
|
* to be called when going down in order to release the ports so that another
|
|
|
|
|
* process may bind to them. It must also be called on disabled proxies at the
|
|
|
|
|
* end of start-up. When all listeners are closed, the proxy is set to the
|
|
|
|
|
* PR_STSTOPPED state.
|
|
|
|
|
*/
|
|
|
|
|
void stop_proxy(struct proxy *p)
|
|
|
|
|
{
|
|
|
|
|
struct listener *l;
|
|
|
|
|
|
2012-09-20 10:48:07 -04:00
|
|
|
list_for_each_entry(l, &p->conf.listeners, by_fe) {
|
2008-10-12 06:07:48 -04:00
|
|
|
unbind_listener(l);
|
|
|
|
|
if (l->state >= LI_ASSIGNED) {
|
|
|
|
|
delete_listener(l);
|
|
|
|
|
listeners--;
|
2010-08-31 09:39:26 -04:00
|
|
|
jobs--;
|
2008-10-12 06:07:48 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
p->state = PR_STSTOPPED;
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
|
2011-09-07 15:33:14 -04:00
|
|
|
/* This function resumes listening on the specified proxy. It scans all of its
|
|
|
|
|
* listeners and tries to enable them all. If any of them fails, the proxy is
|
|
|
|
|
* put back to the paused state. It returns 1 upon success, or zero if an error
|
|
|
|
|
* is encountered.
|
|
|
|
|
*/
|
|
|
|
|
int resume_proxy(struct proxy *p)
|
|
|
|
|
{
|
|
|
|
|
struct listener *l;
|
|
|
|
|
int fail;
|
|
|
|
|
|
|
|
|
|
if (p->state != PR_STPAUSED)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
Warning("Enabling %s %s.\n", proxy_cap_str(p->cap), p->id);
|
|
|
|
|
send_log(p, LOG_WARNING, "Enabling %s %s.\n", proxy_cap_str(p->cap), p->id);
|
|
|
|
|
|
|
|
|
|
fail = 0;
|
2012-09-20 10:48:07 -04:00
|
|
|
list_for_each_entry(l, &p->conf.listeners, by_fe) {
|
2011-09-07 15:33:14 -04:00
|
|
|
if (!resume_listener(l)) {
|
|
|
|
|
int port;
|
|
|
|
|
|
|
|
|
|
port = get_host_port(&l->addr);
|
|
|
|
|
if (port) {
|
|
|
|
|
Warning("Port %d busy while trying to enable %s %s.\n",
|
|
|
|
|
port, proxy_cap_str(p->cap), p->id);
|
|
|
|
|
send_log(p, LOG_WARNING, "Port %d busy while trying to enable %s %s.\n",
|
|
|
|
|
port, proxy_cap_str(p->cap), p->id);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Warning("Bind on socket %d busy while trying to enable %s %s.\n",
|
|
|
|
|
l->luid, proxy_cap_str(p->cap), p->id);
|
|
|
|
|
send_log(p, LOG_WARNING, "Bind on socket %d busy while trying to enable %s %s.\n",
|
|
|
|
|
l->luid, proxy_cap_str(p->cap), p->id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Another port might have been enabled. Let's stop everything. */
|
|
|
|
|
fail = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p->state = PR_STREADY;
|
|
|
|
|
if (fail) {
|
|
|
|
|
pause_proxy(p);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
/*
|
|
|
|
|
* This function temporarily disables listening so that another new instance
|
|
|
|
|
* can start listening. It is designed to be called upon reception of a
|
|
|
|
|
* SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
|
|
|
|
|
* the proxy, or a SIGTTIN can be sent to listen again.
|
|
|
|
|
*/
|
|
|
|
|
void pause_proxies(void)
|
|
|
|
|
{
|
|
|
|
|
int err;
|
|
|
|
|
struct proxy *p;
|
2010-09-23 12:44:36 -04:00
|
|
|
struct peers *prs;
|
2006-06-25 20:48:02 -04:00
|
|
|
|
|
|
|
|
err = 0;
|
|
|
|
|
p = proxy;
|
2008-06-23 08:00:57 -04:00
|
|
|
tv_update_date(0,1); /* else, the old time before select will be used */
|
2006-06-25 20:48:02 -04:00
|
|
|
while (p) {
|
2011-09-07 13:14:57 -04:00
|
|
|
err |= !pause_proxy(p);
|
2006-06-25 20:48:02 -04:00
|
|
|
p = p->next;
|
|
|
|
|
}
|
2010-09-23 12:44:36 -04:00
|
|
|
|
|
|
|
|
prs = peers;
|
|
|
|
|
while (prs) {
|
|
|
|
|
p = prs->peers_fe;
|
2011-09-07 13:14:57 -04:00
|
|
|
err |= !pause_proxy(p);
|
|
|
|
|
prs = prs->next;
|
2010-09-23 12:44:36 -04:00
|
|
|
}
|
|
|
|
|
|
2006-06-25 20:48:02 -04:00
|
|
|
if (err) {
|
|
|
|
|
Warning("Some proxies refused to pause, performing soft stop now.\n");
|
|
|
|
|
send_log(p, LOG_WARNING, "Some proxies refused to pause, performing soft stop now.\n");
|
|
|
|
|
soft_stop();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This function reactivates listening. This can be used after a call to
|
|
|
|
|
* sig_pause(), for example when a new instance has failed starting up.
|
|
|
|
|
* It is designed to be called upon reception of a SIGTTIN.
|
|
|
|
|
*/
|
2011-07-24 12:28:10 -04:00
|
|
|
void resume_proxies(void)
|
2006-06-25 20:48:02 -04:00
|
|
|
{
|
2011-09-07 15:33:14 -04:00
|
|
|
int err;
|
2006-06-25 20:48:02 -04:00
|
|
|
struct proxy *p;
|
2011-09-07 15:33:14 -04:00
|
|
|
struct peers *prs;
|
2006-06-25 20:48:02 -04:00
|
|
|
|
2011-09-07 15:33:14 -04:00
|
|
|
err = 0;
|
2006-06-25 20:48:02 -04:00
|
|
|
p = proxy;
|
2008-06-23 08:00:57 -04:00
|
|
|
tv_update_date(0,1); /* else, the old time before select will be used */
|
2006-06-25 20:48:02 -04:00
|
|
|
while (p) {
|
2011-09-07 15:33:14 -04:00
|
|
|
err |= !resume_proxy(p);
|
2006-06-25 20:48:02 -04:00
|
|
|
p = p->next;
|
|
|
|
|
}
|
2011-09-07 15:33:14 -04:00
|
|
|
|
|
|
|
|
prs = peers;
|
|
|
|
|
while (prs) {
|
|
|
|
|
p = prs->peers_fe;
|
|
|
|
|
err |= !resume_proxy(p);
|
|
|
|
|
prs = prs->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
|
Warning("Some proxies refused to resume, a restart is probably needed to resume safe operations.\n");
|
|
|
|
|
send_log(p, LOG_WARNING, "Some proxies refused to resume, a restart is probably needed to resume safe operations.\n");
|
|
|
|
|
}
|
2006-06-25 20:48:02 -04:00
|
|
|
}
|
|
|
|
|
|
REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-02 18:22:06 -04:00
|
|
|
/* Set current stream's backend to <be>. Nothing is done if the
|
|
|
|
|
* stream already had a backend assigned, which is indicated by
|
2015-04-02 19:14:29 -04:00
|
|
|
* s->flags & SF_BE_ASSIGNED.
|
2009-07-07 09:10:31 -04:00
|
|
|
* All flags, stats and counters which need be updated are updated.
|
2009-07-12 02:27:39 -04:00
|
|
|
* Returns 1 if done, 0 in case of internal error, eg: lack of resource.
|
2009-07-07 09:10:31 -04:00
|
|
|
*/
|
REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-02 18:22:06 -04:00
|
|
|
int stream_set_backend(struct stream *s, struct proxy *be)
|
2009-07-07 09:10:31 -04:00
|
|
|
{
|
2015-04-02 19:14:29 -04:00
|
|
|
if (s->flags & SF_BE_ASSIGNED)
|
2009-07-12 02:27:39 -04:00
|
|
|
return 1;
|
2009-07-07 09:10:31 -04:00
|
|
|
s->be = be;
|
|
|
|
|
be->beconn++;
|
2011-03-10 17:25:56 -05:00
|
|
|
if (be->beconn > be->be_counters.conn_max)
|
|
|
|
|
be->be_counters.conn_max = be->beconn;
|
2009-07-07 09:10:31 -04:00
|
|
|
proxy_inc_be_ctr(be);
|
|
|
|
|
|
REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-02 18:22:06 -04:00
|
|
|
/* assign new parameters to the stream from the new backend */
|
[MEDIUM] new option "independant-streams" to stop updating read timeout on writes
By default, when data is sent over a socket, both the write timeout and the
read timeout for that socket are refreshed, because we consider that there is
activity on that socket, and we have no other means of guessing if we should
receive data or not.
While this default behaviour is desirable for almost all applications, there
exists a situation where it is desirable to disable it, and only refresh the
read timeout if there are incoming data. This happens on sessions with large
timeouts and low amounts of exchanged data such as telnet session. If the
server suddenly disappears, the output data accumulates in the system's
socket buffers, both timeouts are correctly refreshed, and there is no way
to know the server does not receive them, so we don't timeout. However, when
the underlying protocol always echoes sent data, it would be enough by itself
to detect the issue using the read timeout. Note that this problem does not
happen with more verbose protocols because data won't accumulate long in the
socket buffers.
When this option is set on the frontend, it will disable read timeout updates
on data sent to the client. There probably is little use of this case. When
the option is set on the backend, it will disable read timeout updates on
data sent to the server. Doing so will typically break large HTTP posts from
slow lines, so use it with caution.
2009-10-03 16:01:18 -04:00
|
|
|
s->si[1].flags &= ~SI_FL_INDEP_STR;
|
|
|
|
|
if (be->options2 & PR_O2_INDEPSTR)
|
|
|
|
|
s->si[1].flags |= SI_FL_INDEP_STR;
|
|
|
|
|
|
2009-07-07 09:10:31 -04:00
|
|
|
if (be->options2 & PR_O2_RSPBUG_OK)
|
|
|
|
|
s->txn.rsp.err_pos = -1; /* let buggy responses pass */
|
2015-04-02 19:14:29 -04:00
|
|
|
s->flags |= SF_BE_ASSIGNED;
|
2009-07-12 03:47:04 -04:00
|
|
|
|
|
|
|
|
/* If the target backend requires HTTP processing, we have to allocate
|
|
|
|
|
* a struct hdr_idx for it if we did not have one.
|
|
|
|
|
*/
|
2013-03-24 02:22:08 -04:00
|
|
|
if (unlikely(!s->txn.hdr_idx.v && be->http_needed)) {
|
2014-04-28 10:13:51 -04:00
|
|
|
s->txn.hdr_idx.size = global.tune.max_http_hdr;
|
2011-10-24 12:15:04 -04:00
|
|
|
if ((s->txn.hdr_idx.v = pool_alloc2(pool2_hdr_idx)) == NULL)
|
2009-07-12 03:47:04 -04:00
|
|
|
return 0; /* not enough memory */
|
2010-05-31 11:01:36 -04:00
|
|
|
|
|
|
|
|
/* and now initialize the HTTP transaction state */
|
|
|
|
|
http_init_txn(s);
|
2009-07-12 03:47:04 -04:00
|
|
|
}
|
|
|
|
|
|
2014-09-30 12:44:22 -04:00
|
|
|
/* If we chain to an HTTP backend running a different HTTP mode, we
|
|
|
|
|
* have to re-adjust the desired keep-alive/close mode to accommodate
|
|
|
|
|
* both the frontend's and the backend's modes.
|
|
|
|
|
*/
|
|
|
|
|
if (s->fe->mode == PR_MODE_HTTP && be->mode == PR_MODE_HTTP &&
|
|
|
|
|
((s->fe->options & PR_O_HTTP_MODE) != (be->options & PR_O_HTTP_MODE)))
|
|
|
|
|
http_adjust_conn_mode(s, &s->txn, &s->txn.req);
|
|
|
|
|
|
2014-03-12 05:41:13 -04:00
|
|
|
/* If an LB algorithm needs to access some pre-parsed body contents,
|
|
|
|
|
* we must not start to forward anything until the connection is
|
|
|
|
|
* confirmed otherwise we'll lose the pointer to these data and
|
|
|
|
|
* prevent the hash from being doable again after a redispatch.
|
|
|
|
|
*/
|
|
|
|
|
if (be->mode == PR_MODE_HTTP &&
|
|
|
|
|
(be->lbprm.algo & (BE_LB_KIND | BE_LB_PARM)) == (BE_LB_KIND_HI | BE_LB_HASH_PRM))
|
|
|
|
|
s->txn.req.flags |= HTTP_MSGF_WAIT_CONN;
|
|
|
|
|
|
2011-05-30 12:10:30 -04:00
|
|
|
if (be->options2 & PR_O2_NODELAY) {
|
2014-11-27 14:45:39 -05:00
|
|
|
s->req.flags |= CF_NEVER_WAIT;
|
|
|
|
|
s->res.flags |= CF_NEVER_WAIT;
|
2011-05-30 12:10:30 -04:00
|
|
|
}
|
|
|
|
|
|
2009-08-16 16:37:44 -04:00
|
|
|
/* We want to enable the backend-specific analysers except those which
|
|
|
|
|
* were already run as part of the frontend/listener. Note that it would
|
|
|
|
|
* be more reliable to store the list of analysers that have been run,
|
|
|
|
|
* but what we do here is OK for now.
|
2009-07-12 03:47:04 -04:00
|
|
|
*/
|
2014-11-27 14:45:39 -05:00
|
|
|
s->req.analysers |= be->be_req_ana & ~(s->listener->analysers);
|
2009-06-30 11:57:00 -04:00
|
|
|
|
2009-07-12 02:27:39 -04:00
|
|
|
return 1;
|
2009-07-07 09:10:31 -04:00
|
|
|
}
|
|
|
|
|
|
2013-06-21 17:16:39 -04:00
|
|
|
static struct cfg_kw_list cfg_kws = {ILH, {
|
2008-07-09 14:34:27 -04:00
|
|
|
{ CFG_LISTEN, "timeout", proxy_parse_timeout },
|
|
|
|
|
{ CFG_LISTEN, "clitimeout", proxy_parse_timeout },
|
|
|
|
|
{ CFG_LISTEN, "contimeout", proxy_parse_timeout },
|
|
|
|
|
{ CFG_LISTEN, "srvtimeout", proxy_parse_timeout },
|
2009-03-05 17:48:25 -05:00
|
|
|
{ CFG_LISTEN, "rate-limit", proxy_parse_rate_limit },
|
2014-04-25 07:58:37 -04:00
|
|
|
{ CFG_LISTEN, "max-keep-alive-queue", proxy_parse_max_ka_queue },
|
2008-07-09 14:34:27 -04:00
|
|
|
{ 0, NULL, NULL },
|
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
__attribute__((constructor))
|
|
|
|
|
static void __proxy_module_init(void)
|
|
|
|
|
{
|
|
|
|
|
cfg_register_keywords(&cfg_kws);
|
|
|
|
|
}
|
2006-06-25 20:48:02 -04:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Local variables:
|
|
|
|
|
* c-indent-level: 8
|
|
|
|
|
* c-basic-offset: 8
|
|
|
|
|
* End:
|
|
|
|
|
*/
|