From 2f6ba6579f170224e620c63f4c347da8ec6375a4 Mon Sep 17 00:00:00 2001 From: willy tarreau Date: Sat, 17 Dec 2005 13:57:42 +0100 Subject: [PATCH] * released 1.1.21 * changed the debug output format so that it now includes the session unique ID followed by the instance name at the beginning of each line. * in debug mode, accept now shows the client's IP and port. * added one 3 small debugging scripts to search and pretty print debug output * changed the default health check request to "OPTIONS /" instead of "OPTIONS *" since not all servers implement the later one. * "option httpchk" now accepts an optional parameter allowing the user to specify and URI other than '/' during health-checks. * made Makefile more robust to pcre-config errors * added 3 new pretty-print scripts : debug2ansi, debug2html and debugfind * upgraded Formilux package to haproxy-1.1.21-flx.1.pkg * removed the now obsolete haproxy2html.sh --- CHANGELOG | 10 +++++++ Makefile | 2 +- doc/haproxy.txt | 35 +++++++++++++++------- examples/debug2ansi | 2 ++ examples/debug2html | 2 ++ examples/debugfind | 8 +++++ examples/haproxy-1.1.12-flx.1.pkg | 18 ------------ examples/haproxy-1.1.21-flx.1.pkg | 21 +++++++++++++ examples/haproxy.cfg | 4 +-- examples/haproxy2html.sh | 3 -- haproxy.c | 49 ++++++++++++++++++++++++------- 11 files changed, 108 insertions(+), 46 deletions(-) create mode 100644 examples/debug2ansi create mode 100644 examples/debug2html create mode 100644 examples/debugfind delete mode 100644 examples/haproxy-1.1.12-flx.1.pkg create mode 100644 examples/haproxy-1.1.21-flx.1.pkg delete mode 100644 examples/haproxy2html.sh diff --git a/CHANGELOG b/CHANGELOG index 47512a73c..59731cc1a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,16 @@ ChangeLog : =========== +2003/05/06 : 1.1.21 + - changed the debug output format so that it now includes the session unique + ID followed by the instance name at the beginning of each line. + - in debug mode, accept now shows the client's IP and port. + - added one 3 small debugging scripts to search and pretty print debug output + - changed the default health check request to "OPTIONS /" instead of + "OPTIONS *" since not all servers implement the later one. + - "option httpchk" now accepts an optional parameter allowing the user to + specify and URI other than '/' during health-checks. + 2003/04/21 : 1.1.20 - fixed two problems with time-outs, one where a server would be logged as timed out during transfer that take longer to complete than the fixed diff --git a/Makefile b/Makefile index 361642061..c3cb104d8 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ REGEX=libc #REGEX=pcre # This is the directory hosting include/pcre.h and lib/libpcre.* when REGEX=pcre -PCREDIR := $(shell pcre-config --prefix 2>/dev/null) +PCREDIR := $(shell pcre-config --prefix 2>/dev/null || :) #PCREDIR=/usr/local # This is for Linux 2.4 with netfilter diff --git a/doc/haproxy.txt b/doc/haproxy.txt index aea6d0cb7..c20c2447f 100644 --- a/doc/haproxy.txt +++ b/doc/haproxy.txt @@ -1,9 +1,9 @@ H A - P r o x y --------------- - version 1.1.18 + version 1.1.21 willy tarreau - 2003/04/06 + 2003/05/06 ================ | Introduction | @@ -588,14 +588,18 @@ Le mode par d 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. Les versions 1.1.16 et 1.1.17 -utilisent "OPTIONS / HTTP/1.0". Depuis la version 1.1.18, les requêtes ont été -changées en "OPTIONS * HTTP/1.0" pour des raisons de contrôle d'accès aux -ressources. 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". +utilisent "OPTIONS / HTTP/1.0". Dans les versions 1.1.18 à 1.1.20, les requêtes +ont été changées en "OPTIONS * HTTP/1.0" pour des raisons de contrôle d'accès aux +ressources. Cependant, cette requête documentée dans la RFC2068 n'est pas +comprise par tous les serveurs. Donc à partir de la version 1.1.21, la requête +par défaut est revenue à "OPTIONS / HTTP/1.0", mais il est possible de +paramétrer la partie URI. Les requêtes OPTIONS 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", éventuellement suivie d'une +URI. Voir les exemples ci-après. Depuis la version 1.1.17, il est possible de définir des serveurs de secours, utilisés uniquement lorsqu'aucun des autres serveurs ne fonctionne. Pour cela, @@ -626,7 +630,7 @@ Exemples : 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 +# même que précédemment avec surveillance HTTP par 'OPTIONS / HTTP/1.0' listen http_proxy 0.0.0.0:80 mode http cookie SERVERID @@ -635,6 +639,15 @@ Exemples : 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 par 'OPTIONS /index.html HTTP/1.0' + listen http_proxy 0.0.0.0:80 + mode http + cookie SERVERID + balance roundrobin + option httpchk /index.html + 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 + # Insertion automatique de cookie dans la réponse du serveur, et suppression # automatique dans la requête, tout en indiquant aux caches de ne pas garder # ce cookie. diff --git a/examples/debug2ansi b/examples/debug2ansi new file mode 100644 index 000000000..6ba345d54 --- /dev/null +++ b/examples/debug2ansi @@ -0,0 +1,2 @@ +#!/bin/sh +tr -d '\015' | sed -e 's,\(: Cookie:.*$\),'$'\e''\[35m\1'$'\e''\[0m,gi' -e 's,\(: Set-Cookie:.*$\),'$'\e''\[31m\1'$'\e''\[0m,gi' -e 's,\(^[^:]*:[^:]*srvhdr.*\)$,'$'\e''\[32m\1'$'\e''\[0m,i' -e 's,\(^[^:]*:[^:]*clihdr.*\)$,'$'\e''\[34m\1'$'\e''\[0m,i' diff --git a/examples/debug2html b/examples/debug2html new file mode 100644 index 000000000..866b76184 --- /dev/null +++ b/examples/debug2html @@ -0,0 +1,2 @@ +#!/bin/sh +(echo '
'; tr -d '\015' | sed -e 's,\(: Cookie:.*$\),\1,gi' -e 's,\(: Set-Cookie:.*$\),\1,gi' -e 's,\(^[^:]*:[^:]*srvhdr.*\)$,\1,i' -e 's,\(^[^:]*:[^:]*clihdr.*\)$,\1,i' -e 's,\(^.*\)$,\1,' ; echo '
') diff --git a/examples/debugfind b/examples/debugfind new file mode 100644 index 000000000..88e97609a --- /dev/null +++ b/examples/debugfind @@ -0,0 +1,8 @@ +#!/bin/bash +if [ $# -lt 2 ]; then + echo "Usage: $0 regex debug_file > extracted_file" + exit 1 +fi +word=$1 +file=$2 +exec grep $(for i in $(grep $word $file |cut -f1 -d: | sort -u ) ; do echo -n '\('$i':\)\|'; done; echo '^$') $file diff --git a/examples/haproxy-1.1.12-flx.1.pkg b/examples/haproxy-1.1.12-flx.1.pkg deleted file mode 100644 index 49ea3f695..000000000 --- a/examples/haproxy-1.1.12-flx.1.pkg +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -function do_compile { - $FLXMAKE COPTS="-march=$arch -mcpu=$cpu -O2 -mpreferred-stack-boundary=2 -malign-loops=0 -malign-jumps=0 -DNETFILTER -DTRANSPARENT" -} - -function do_prepack { - mkdir -p $ROOTDIR/sbin/init.d ; cp init.d/haproxy $ROOTDIR/sbin/init.d - mkdir -p $ROOTDIR/usr/sbin ; cp haproxy $ROOTDIR/usr/sbin - mkdir -p $ROOTDIR/usr/share/examples/$PKGRADIX-$PKGVER/etc - cp examples/haproxy.cfg $ROOTDIR/usr/share/examples/$PKGRADIX-$PKGVER/etc/haproxy.cfg - cp examples/rc.highsock $ROOTDIR/usr/share/examples/$PKGRADIX-$PKGVER/etc/rc.highsock - cp examples/config.rc.haproxy $ROOTDIR/usr/share/examples/$PKGRADIX-$PKGVER/etc/config.rc.haproxy - mkdir -p $ROOTDIR/usr/share/$PKGRADIX-$PKGVER ; cp doc/haproxy.txt $ROOTDIR/usr/share/$PKGRADIX-$PKGVER - ln -s ../examples/$PKGRADIX-$PKGVER $ROOTDIR/usr/share/$PKGRADIX-$PKGVER/examples - make clean -} - diff --git a/examples/haproxy-1.1.21-flx.1.pkg b/examples/haproxy-1.1.21-flx.1.pkg new file mode 100644 index 000000000..8054ffdd8 --- /dev/null +++ b/examples/haproxy-1.1.21-flx.1.pkg @@ -0,0 +1,21 @@ +#!/bin/sh + +function do_compile { + $FLXMAKE COPTS="-march=$arch -mcpu=$cpu -Os -mpreferred-stack-boundary=2 -momit-leaf-frame-pointer -malign-jumps=0 -DNETFILTER -DTRANSPARENT" +} + +function do_prepack { + mkdir -p $ROOTDIR/sbin/init.d ; cp init.d/haproxy $ROOTDIR/sbin/init.d + mkdir -p $ROOTDIR/usr/sbin ; cp haproxy $ROOTDIR/usr/sbin + mkdir -p $ROOTDIR/usr/share/examples/$PKGRADIX/$PKGRADIX-$PKGVER/etc + cp examples/haproxy.cfg $ROOTDIR/usr/share/examples/$PKGRADIX/$PKGRADIX-$PKGVER/etc/haproxy.cfg + cp examples/rc.highsock $ROOTDIR/usr/share/examples/$PKGRADIX/$PKGRADIX-$PKGVER/etc/rc.highsock + cp examples/config.rc.haproxy $ROOTDIR/usr/share/examples/$PKGRADIX/$PKGRADIX-$PKGVER/etc/config.rc.haproxy + mkdir -p $ROOTDIR/usr/share/$PKGRADIX/$PKGRADIX-$PKGVER + cp doc/haproxy.txt $ROOTDIR/usr/share/$PKGRADIX/$PKGRADIX-$PKGVER + ln -s ../../examples/$PKGRADIX/$PKGRADIX-$PKGVER $ROOTDIR/usr/share/$PKGRADIX/$PKGRADIX-$PKGVER/examples + cp examples/debug2ansi examples/debug2html examples/debugfind $ROOTDIR/usr/share/$PKGRADIX/$PKGRADIX-$PKGVER/ + + make clean +} + diff --git a/examples/haproxy.cfg b/examples/haproxy.cfg index 3b6f8259d..b6d877f5a 100644 --- a/examples/haproxy.cfg +++ b/examples/haproxy.cfg @@ -70,7 +70,7 @@ listen appli4-backup 0.0.0.0:10004 mode http option httplog option dontlognull - option httpchk + option httpchk /index.html option persist balance roundrobin server inst1 192.168.114.56:80 check inter 2000 fall 3 @@ -87,7 +87,7 @@ listen appli5-backup 0.0.0.0:10005 mode http option httplog option dontlognull - option httpchk + 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/examples/haproxy2html.sh b/examples/haproxy2html.sh deleted file mode 100644 index e3753c72a..000000000 --- a/examples/haproxy2html.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -#(echo ''; sed -e 's,\(ASPSESSIONID[^; ]*\),\1,g' -e 's,\(^srvhdr.*\)$,\1,' -e 's,\(^clihdr.*\)$,\1,' -e 's,\(^.*\)$,\1,' -e 's/$/
/' ; echo '') -(echo ''; tr -d '\015' | sed -e 's,\(: Cookie:.*$\),\1,gi' -e 's,\(: Set-Cookie:.*$\),\1,gi' -e 's,\(^srvhdr.*\)$,\1,i' -e 's,\(^clihdr.*\)$,\1,i' -e 's,\(^.*\)$,\1,' -e 's/$/
/' ; echo '') diff --git a/haproxy.c b/haproxy.c index 5c3572641..ff880a6ed 100644 --- a/haproxy.c +++ b/haproxy.c @@ -53,8 +53,8 @@ #include #endif -#define HAPROXY_VERSION "1.1.20" -#define HAPROXY_DATE "2003/04/21" +#define HAPROXY_VERSION "1.1.21" +#define HAPROXY_DATE "2003/05/06" /* this is for libc5 for example */ #ifndef TCP_NODELAY @@ -94,6 +94,7 @@ #define DEF_CHKINTR 2000 #define DEF_FALLTIME 3 #define DEF_RISETIME 2 +#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n" /* default connections limit */ #define DEFAULT_MAXCONN 2000 @@ -402,6 +403,7 @@ struct session { int status; /* HTTP status from the server, negative if from proxy */ long long bytes; /* number of bytes transferred from the server */ } logs; + unsigned int uniq_id; /* unique ID used for the traces */ }; struct proxy { @@ -437,6 +439,8 @@ struct proxy { struct hdr_exp *rsp_exp; /* regular expressions for response headers */ char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */ int grace; /* grace time after stop request */ + char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */ + int check_len; /* Length of the HTTP request */ struct { char *msg400; /* message for error 400 */ int len400; /* message length for error 400 */ @@ -1994,6 +1998,8 @@ int event_accept(int fd) { s->logs.status = -1; s->logs.bytes = 0; + s->uniq_id = totalconn; + if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP) && (p->logfac1 >= 0 || p->logfac2 >= 0)) { struct sockaddr_in sockname; @@ -2020,8 +2026,20 @@ int event_accept(int fd) { } if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) { + struct sockaddr_in sockname; + unsigned char *pn, *sn; + int namelen; int len; - len = sprintf(trash, "accept(%04x)=%04x\n", (unsigned short)fd, (unsigned short)cfd); + + namelen = sizeof(sockname); + if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1) + getsockname(cfd, (struct sockaddr *)&sockname, &namelen); + sn = (unsigned char *)&sockname.sin_addr; + pn = (unsigned char *)&s->cli_addr.sin_addr; + + len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%d.%d.%d.%d:%d]\n", + s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd, + pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port)); write(1, trash, len); } @@ -2108,13 +2126,13 @@ int event_srv_chk_w(int fd) { else { if (s->proxy->options & PR_O_HTTP_CHK) { int ret; - /* we want to check if this host replies to "OPTIONS * HTTP/1.0" + /* 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); + ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT); #else - ret = send(fd, "OPTIONS * HTTP/1.0\r\n\r\n", 22, MSG_DONTWAIT | MSG_NOSIGNAL); + ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL); #endif if (ret == 22) { FD_SET(fd, StaticReadEvent); /* prepare for reading reply */ @@ -2399,7 +2417,7 @@ int process_cli(struct session *t) { if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) { int len, max; - len = sprintf(trash, "clihdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd); + len = sprintf(trash, "%08x:%s.clihdr[%04x:%04x]: ", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd); max = ptr - req->h; UBOUND(max, sizeof(trash) - len - 1); len += strlcpy2(trash + len, req->h, max + 1); @@ -2860,7 +2878,7 @@ int process_cli(struct session *t) { else { /* CL_STCLOSE: nothing to do */ if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) { int len; - len = sprintf(trash, "clicls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd); + len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd); write(1, trash, len); } return 0; @@ -3100,7 +3118,7 @@ int process_srv(struct session *t) { if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) { int len, max; - len = sprintf(trash, "srvhdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd); + len = sprintf(trash, "%08x:%s.srvhdr[%04x:%04x]: ", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd); max = ptr - rep->h; UBOUND(max, sizeof(trash) - len - 1); len += strlcpy2(trash + len, rep->h, max + 1); @@ -3548,7 +3566,7 @@ int process_srv(struct session *t) { else { /* SV_STCLOSE : nothing to do */ if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) { int len; - len = sprintf(trash, "srvcls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd); + len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd); write(1, trash, len); } return 0; @@ -3595,7 +3613,7 @@ int process_session(struct task *t) { if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) { int len; - len = sprintf(trash, "closed[%04x:%04x]\n", (unsigned short)s->cli_fd, (unsigned short)s->srv_fd); + len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n", s->uniq_id, s->proxy->id, (unsigned short)s->cli_fd, (unsigned short)s->srv_fd); write(1, trash, len); } @@ -4424,6 +4442,15 @@ int cfg_parse_listen(char *file, int linenum, char **args) { else if (!strcmp(args[1], "httpchk")) { /* use HTTP request to check servers' health */ curproxy->options |= PR_O_HTTP_CHK; + if (*args[2]) { + int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n"); + curproxy->check_req = (char *)malloc(reqlen); + curproxy->check_len = snprintf(curproxy->check_req, reqlen, + "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */ + } else { + curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */ + curproxy->check_len = strlen(DEF_CHECK_REQ); + } } else if (!strcmp(args[1], "persist")) { /* persist on using the server specified by the cookie, even when it's down */