From: willy tarreau Date: Sat, 17 Dec 2005 12:32:07 +0000 (+0100) Subject: * released 1.1.16 X-Git-Tag: v1.1.16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bc4e1fb68ad6040abce91c0c64edbe51960f123b;p=thirdparty%2Fhaproxy.git * released 1.1.16 * implement HTTP health checks when option "httpchk" is specified. * put the changelog into a new CHANGELOG file * updated the Formilux init script --- diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000000..e7d93a8d50 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,130 @@ + * ChangeLog : + * + * 2002/09/01 : 1.1.16 + * - implement HTTP health checks when option "httpchk" is specified. + * 2002/08/07 : 1.1.15 + * - replaced setpgid()/setpgrp() with setsid() for better portability, because + * setpgrp() doesn't have the same meaning under Solaris, Linux, and OpenBSD. + * 2002/07/20 : 1.1.14 + * - added "postonly" cookie mode + * 2002/07/15 : 1.1.13 + * - tv_diff used inverted parameters which led to negative times ! + * 2002/07/13 : 1.1.12 + * - fixed stats monitoring, and optimized some tv_* for most common cases. + * - replaced temporary 'newhdr' with 'trash' to reduce stack size + * - made HTTP errors more HTML-fiendly. + * - renamed strlcpy() to strlcpy2() because of a slightly difference between + * their behaviour (return value), to avoid confusion. + * - restricted HTTP messages to HTTP proxies only + * - added a 502 message when the connection has been refused by the server, + * to prevent clients from believing this is a zero-byte HTTP 0.9 reply. + * - changed 'Cache-control:' from 'no-cache="set-cookie"' to 'private' when + * inserting a cookie, because some caches (apache) don't understand it. + * - fixed processing of server headers when client is in SHUTR state + * 2002/07/04 : + * - automatically close fd's 0,1 and 2 when going daemon ; setpgrp() after + * setpgid() + * 2002/06/04 : 1.1.11 + * - fixed multi-cookie handling in client request to allow clean deletion + * in insert+indirect mode. Now, only the server cookie is deleted and not + * all the header. Should now be compliant to RFC2109. + * - added a "nocache" option to "cookie" to specify that we explicitly want + * to add a "cache-control" header when we add a cookie. + * It is also possible to add an "Expires: " to keep compatibility + * with old/broken caches. + * 2002/05/10 : 1.1.10 + * - if a cookie is used in insert+indirect mode, it's desirable that the + * the servers don't see it. It was not possible to remove it correctly + * with regexps, so now it's removed automatically. + * 2002/04/19 : 1.1.9 + * - don't use snprintf()'s return value as an end of message since it may + * be larger. This caused bus errors and segfaults in internal libc's + * getenv() during localtime() in send_log(). + * - removed dead insecure send_syslog() function and all references to it. + * - fixed warnings on Solaris due to buggy implementation of isXXXX(). + * 2002/04/18 : 1.1.8 + * - option "dontlognull" + * - fixed "double space" bug in config parser + * - fixed an uninitialized server field in case of dispatch + * with no existing server which could cause a segfault during + * logging. + * - the pid logged was always the father's, which was wrong for daemons. + * - fixed wrong level "LOG_INFO" for message "proxy started". + * 2002/04/13 : + * - http logging is now complete : + * - ip:port, date, proxy, server + * - req_time, conn_time, hdr_time, tot_time + * - status, size, request + * - source address + * 2002/04/12 : 1.1.7 + * - added option forwardfor + * - added reqirep, reqidel, reqiallow, reqideny, rspirep, rspidel + * - added "log global" in "listen" section. + * 2002/04/09 : + * - added a new "global" section : + * - logs + * - debug, quiet, daemon modes + * - uid, gid, chroot, nbproc, maxconn + * 2002/04/08 : 1.1.6 + * - regex are now chained and not limited anymore. + * - unavailable server now returns HTTP/502. + * - increased per-line args limit to 40 + * - added reqallow/reqdeny to block some request on matches + * - added HTTP 400/403 responses + * 2002/04/03 : 1.1.5 + * - connection logging displayed incorrect source address. + * - added proxy start/stop and server up/down log events. + * - replaced log message short buffers with larger trash. + * - enlarged buffer to 8 kB and replace buffer to 4 kB. + * 2002/03/25 : 1.1.4 + * - made rise/fall/interval time configurable + * 2002/03/22 : 1.1.3 + * - fixed a bug : cr_expire and cw_expire were inverted in CL_STSHUT[WR] + * which could lead to loops. + * 2002/03/21 : 1.1.2 + * - fixed a bug in buffer management where we could have a loop + * between event_read() and process_{cli|srv} if R==BUFSIZE-MAXREWRITE. + * => implemented an adjustable buffer limit. + * - fixed a bug : expiration of tasks in wait queue timeout is used again, + * and running tasks are skipped. + * - added some debug lines for accept events. + * - send warnings for servers up/down. + * 2002/03/12 : 1.1.1 + * - fixed a bug in total failure handling + * - fixed a bug in timestamp comparison within same second (tv_cmp_ms) + * 2002/03/10 : 1.1.0 + * - fixed a few timeout bugs + * - rearranged the task scheduler subsystem to improve performance, + * add new tasks, and make it easier to later port to librt ; + * - allow multiple accept() for one select() wake up ; + * - implemented internal load balancing with basic health-check ; + * - cookie insertion and header add/replace/delete, with better strings + * support. + * 2002/03/08 + * - reworked buffer handling to fix a few rewrite bugs, and + * improve overall performance. + * - implement the "purge" option to delete server cookies in direct mode. + * 2002/03/07 + * - fixed some error cases where the maxfd was not decreased. + * 2002/02/26 + * - now supports transparent proxying, at least on linux 2.4. + * 2002/02/12 + * - soft stop works again (fixed select timeout computation). + * - it seems that TCP proxies sometimes cannot timeout. + * - added a "quiet" mode. + * - enforce file descriptor limitation on socket() and accept(). + * 2001/12/30 : release of version 1.0.2 : fixed a bug in header processing + * 2001/12/19 : release of version 1.0.1 : no MSG_NOSIGNAL on solaris + * 2001/12/16 : release of version 1.0.0. + * 2001/12/16 : added syslog capability for each accepted connection. + * 2001/11/19 : corrected premature end of files and occasional SIGPIPE. + * 2001/10/31 : added health-check type servers (mode health) which replies OK then closes. + * 2001/10/30 : added the ability to support standard TCP proxies and HTTP proxies + * with or without cookies (use keyword http for this). + * 2001/09/01 : added client/server header replacing with regexps. + * eg: + * cliexp ^(Host:\ [^:]*).* Host:\ \1:80 + * srvexp ^Server:\ .* Server:\ Apache + * 2000/11/29 : first fully working release with complete FSMs and timeouts. + * 2000/11/28 : major rewrite + * 2000/11/26 : first write diff --git a/TODO b/TODO index 97236802d6..7d8ef742f3 100644 --- a/TODO +++ b/TODO @@ -22,7 +22,7 @@ matchée dans la "session" pour accélérer les regex. - gestion keep-alive -- handle parametrable HTTP health-checks replies ++ handle parametrable HTTP health-checks replies - differentiate http headers and http uris - support environment variables in config file - support keep-alive diff --git a/doc/haproxy.txt b/doc/haproxy.txt index b9b0aee26b..06ed2f9f02 100644 --- a/doc/haproxy.txt +++ b/doc/haproxy.txt @@ -1,9 +1,9 @@ H A - P r o x y --------------- - version 1.1.14 + version 1.1.16 willy tarreau - 2002/07/20 + 2002/09/01 ================ | Introduction | @@ -556,10 +556,9 @@ Exemple : m 3.1) Surveillance des serveurs ------------------------------ -A cette date, l'état des serveurs n'est testé que par établissement de connexion -TCP toutes les 2 secondes, avec 3 essais pour déclarer un serveur en panne, 2 -pour le déclarer utilisable. Un serveur hors d'usage ne sera pas utilisé dans le -processus de répartition de charge interne. Pour activer la surveillance, +Il est possible de tester l'état des serveurs par établissement de connexion TCP +ou par envoi d'une requête HTTP. Un serveur hors d'usage ne sera pas utilisé +dans leprocessus de répartition de charge interne. Pour activer la surveillance, ajouter le mot clé 'check' à la fin de la déclaration du serveur. Il est possible de spécifier l'intervalle (en millisecondes) séparant deux tests du serveur par le paramètre "inter", le nombre d'échecs acceptés par le paramètre @@ -569,13 +568,32 @@ param - rise : 2 - fall : 3 +Le mode par défaut consiste à établir des connexions TCP uniquement. Dans +certains cas de pannes, des serveurs peuvent continuer à accepter les connexions +sans les traiter. Depuis la version 1.1.16, haproxy est en mesure d'envoyer des +requêtes HTTP courtes et très peu coûteuses : "OPTIONS / HTTP/1.0". Elles +présentent l'avantage d'être facilement extractibles des logs, et de ne pas +induire d'accès aux fichiers côté serveur. Seules les réponses 2xx et 3xx sont +considérées valides, les autres (y compris non-réponses) aboutissent à un échec. +Le temps maximal imparti pour une réponse est égal à l'intervalle entre deux +tests (paramètre "inter"). Pour activer ce mode, spécifier l'option "httpchk". + Exemples : ---------- -# même que précédemment avec surveillance +# même que précédemment avec surveillance TCP + listen http_proxy 0.0.0.0:80 + mode http + cookie SERVERID + balance roundrobin + server web1 192.168.1.1:80 cookie server01 check + server web2 192.168.1.2:80 cookie server02 check inter 500 rise 1 fall 2 + +# même que précédemment avec surveillance HTTP listen http_proxy 0.0.0.0:80 mode http cookie SERVERID balance roundrobin + option httpchk server web1 192.168.1.1:80 cookie server01 check server web2 192.168.1.2:80 cookie server02 check inter 500 rise 1 fall 2 diff --git a/examples/examples.cfg b/examples/examples.cfg index b3bff69de9..8bec8288fe 100644 --- a/examples/examples.cfg +++ b/examples/examples.cfg @@ -23,7 +23,9 @@ listen proxy1 0.0.0.0:8000 #dispatch 127.0.0.1:31300 #dispatch 127.0.0.1:80 #dispatch 127.0.0.1:22 - server nc 127.0.0.1:8080 cookie cookie1 check + option httpchk + server test 10.1.1.2:80 cookie cookie1 check inter 300 +# server nc 127.0.0.1:8080 cookie cookie1 check inter 300 # server tuxlocal0 10.101.23.9:80 cookie cookie1 check # server tuxlocal1 127.0.0.1:80 cookie cookie1 check # server tuxlocal2 127.0.0.1:80 cookie cookie2 check diff --git a/examples/haproxy.cfg b/examples/haproxy.cfg index 4e8b4342e4..97ef70bdfb 100644 --- a/examples/haproxy.cfg +++ b/examples/haproxy.cfg @@ -31,6 +31,7 @@ listen appli2-insert 0.0.0.0:10002 mode http option httplog option dontlognull + option httpchk balance roundrobin cookie SERVERID insert indirect nocache server inst1 192.168.114.56:80 cookie server01 check inter 2000 fall 3 diff --git a/haproxy.c b/haproxy.c index d51ea2d24f..0dfa46e4e7 100644 --- a/haproxy.c +++ b/haproxy.c @@ -18,6 +18,8 @@ * * ChangeLog : * + * 2002/09/01 : 1.1.16 + * - implement HTTP health checks when option "httpchk" is specified. * 2002/08/07 : 1.1.15 * - replaced setpgid()/setpgrp() with setsid() for better portability, because * setpgrp() doesn't have the same meaning under Solaris, Linux, and OpenBSD. @@ -147,7 +149,6 @@ * * TODO: * - handle properly intermediate incomplete server headers. Done ? - * - log proxies start/stop * - handle hot-reconfiguration * */ @@ -176,8 +177,8 @@ #include #endif -#define HAPROXY_VERSION "1.1.15" -#define HAPROXY_DATE "2002/08/07" +#define HAPROXY_VERSION "1.1.16" +#define HAPROXY_DATE "2002/09/01" /* this is for libc5 for example */ #ifndef TCP_NODELAY @@ -342,6 +343,7 @@ int strlcpy2(char *dst, const char *src, int size) { #define PR_O_NULLNOLOG 512 /* a connect without request will not be logged */ #define PR_O_COOK_NOC 1024 /* add a 'Cache-control' header with the cookie */ #define PR_O_COOK_POST 2048 /* don't insert cookies for requests other than a POST */ +#define PR_O_HTTP_CHK 4096 /* use HTTP 'OPTIONS' method to check server health */ /* various session flags */ @@ -2061,10 +2063,11 @@ int event_accept(int fd) { /* * This function is used only for server health-checks. It handles - * the connection acknowledgement and returns 1 if the socket is OK, + * the connection acknowledgement. If the proxy requires HTTP health-checks, + * it sends the request. In other cases, it returns 1 if the socket is OK, * or -1 if an error occured. */ -int event_srv_hck(int fd) { +int event_srv_chk_w(int fd) { struct task *t = fdtab[fd].owner; struct server *s = t->context; @@ -2073,9 +2076,64 @@ int event_srv_hck(int fd) { getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr); if (skerr) s->result = -1; - else - s->result = 1; + else { + if (s->proxy->options & PR_O_HTTP_CHK) { + int ret; + /* we want to check if this host replies to "OPTIONS / HTTP/1.0" + * so we'll send the request, and won't wake the checker up now. + */ +#ifndef MSG_NOSIGNAL + ret = send(fd, "OPTIONS / HTTP/1.0\r\n\r\n", 22, MSG_DONTWAIT); +#else + ret = send(fd, "OPTIONS / HTTP/1.0\r\n\r\n", 22, MSG_DONTWAIT | MSG_NOSIGNAL); +#endif + if (ret == 22) { + FD_SET(fd, StaticReadEvent); /* prepare for reading reply */ + FD_CLR(fd, StaticWriteEvent); /* nothing more to write */ + return 0; + } + else + s->result = -1; + } + else { + /* good TCP connection is enough */ + s->result = 1; + } + } + + task_wakeup(&rq, t); + return 0; +} + +/* + * This function is used only for server health-checks. It handles + * the server's reply to an HTTP request. It returns 1 if the server replies + * 2xx or 3xx (valid responses), or -1 in other cases. + */ +int event_srv_chk_r(int fd) { + char reply[64]; + int len; + struct task *t = fdtab[fd].owner; + struct server *s = t->context; + + int skerr, lskerr; + lskerr = sizeof(skerr); + getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr); + s->result = -1; + if (!skerr) { +#ifndef MSG_NOSIGNAL + len = recv(fd, reply, sizeof(reply), 0); +#else + len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL); +#endif + if ((len >= sizeof("HTTP/1.0 000")) && + !memcmp(reply, "HTTP/1.", 7) && + (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */ + s->result = 1; + } + + FD_CLR(fd, StaticReadEvent); task_wakeup(&rq, t); return 0; } @@ -3277,8 +3335,8 @@ int process_chk(struct task *t) { s->curfd = fd; /* that's how we know a test is in progress ;-) */ fdtab[fd].owner = t; - fdtab[fd].read = NULL; - fdtab[fd].write = &event_srv_hck; + fdtab[fd].read = &event_srv_chk_r; + fdtab[fd].write = &event_srv_chk_w; fdtab[fd].state = FD_STCONN; /* connection in progress */ FD_SET(fd, StaticWriteEvent); /* for connect status */ fd_insert(fd); @@ -3981,6 +4039,10 @@ int cfg_parse_listen(char *file, int linenum, char **args) { /* don't log empty requests */ curproxy->options |= PR_O_NULLNOLOG; } + else if (!strcmp(args[1], "httpchk")) { + /* use HTTP request to check servers' health */ + curproxy->options |= PR_O_HTTP_CHK; + } else { Alert("parsing [%s:%d] : unknown option <%s>.\n", file, linenum, args[1]); return -1; diff --git a/init.d/haproxy b/init.d/haproxy index 3849d701ae..89e3b83382 100644 --- a/init.d/haproxy +++ b/init.d/haproxy @@ -31,7 +31,7 @@ ulimit -n $maxfd # ulimit -c unlimited # soft stop -function dostop { +function do_stop { pids=`pidof -o $$ -- $PNAME` if [ ! -z "$pids" ]; then echo "Asking $PNAME to terminate gracefully..."