From: willy tarreau Date: Sun, 18 Dec 2005 00:08:26 +0000 (+0100) Subject: * released 1.2.5-pre2 X-Git-Tag: v1.2.5-pre2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c1f4753d6073cbc276903a9cbce5a58787052a67;p=thirdparty%2Fhaproxy.git * released 1.2.5-pre2 * implemented the HTTP 303 code for error redirection. This forces the browser to fetch the given URI with a GET request. The new keyword for this is 'errorloc303', and a new 'errorloc302' keyword has been created to make them easily distinguishable. * added more controls in the parser for valid use of '\x' sequence. * few fixes from Alex & Klaus * fixed a few errors in the documentation * do not pre-initialize unused file-descriptors before select() anymore. --- diff --git a/CHANGELOG b/CHANGELOG index df96dd6d85..f0af36f44b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,20 @@ ChangeLog : =========== +2005/04/24 + - implemented the HTTP 303 code for error redirection. This forces the + browser to fetch the given URI with a GET request. The new keyword for + this is 'errorloc303', and a new 'errorloc302' keyword has been created + to make them easily distinguishable. + - added more controls in the parser for valid use of '\x' sequence. + - few fixes from Alex & Klaus + +2005/02/17 + - fixed a few errors in the documentation + +2005/02/13 + - do not pre-initialize unused file-descriptors before select() anymore. + 2005/01/22 : 1.2.4 - merged Alexander Lazic's and Klaus Wagner's work on application cookie-based persistence. Since this is the first merge, this version is diff --git a/doc/haproxy-en.txt b/doc/haproxy-en.txt index ab14dcf1e4..65ebb96d6e 100644 --- a/doc/haproxy-en.txt +++ b/doc/haproxy-en.txt @@ -2,9 +2,9 @@ H A - P r o x y Reference Manual ------------------- - version 1.2.3 + version 1.2.5 willy tarreau - 2005/01/22 + 2005/04/24 ============ | Abstract | @@ -1555,6 +1555,18 @@ Example : errorloc 503 http://192.168.114.58/error50x.html errorloc 504 http://192.168.114.58/error50x.html +Note: RFC2616 says that a client must reuse the same method to fetch the +Location returned by a 302, which causes problems with the POST method. +The return code 303 was designed explicitly to force the client to fetch the +Location URL with the GET method, but there are some browsers pre-dating +HTTP/1.1 which don't support it. Anyway, most browsers still behave with 302 as +if it was a 303. In order to allow the user to chose, version 1.2.5 brings two +new keywords to replace 'errorloc' : 'errorloc302' and 'errorloc303'. + +They are preffered over errorloc (which still does 302). Consider using +errorloc303 everytime you know that your clients support HTTP 303 responses.. + + 4.7) Modifying default values ----------------------------- Version 1.1.22 introduced the notion of default values, which eliminates the diff --git a/doc/haproxy-fr.txt b/doc/haproxy-fr.txt index 1db2bc4674..109c45cec8 100644 --- a/doc/haproxy-fr.txt +++ b/doc/haproxy-fr.txt @@ -2,9 +2,9 @@ H A - P r o x y Manuel de référence ------------------- - version 1.2.3 + version 1.2.5 willy tarreau - 2005/01/22 + 2005/04/24 ================ | Introduction | @@ -1578,6 +1578,21 @@ Exemple : errorloc 503 http://192.168.114.58/error50x.html errorloc 504 http://192.168.114.58/error50x.html +Note: la RFC2616 stipule qu'un client doit réutiliser la même méthode pour +accéder à l'URL de redirection que celle qui l'a retournée, ce qui pose des +problèmes avec les requêtes POST. Le code de retour 303 a été créé exprès pour +régler ce problème, indiquant au client qu'il doit accéder à l'URL retournée +dans le champ Location avec la méthode GET uniquement. Seulement, certains +navigateurs antérieurs à HTTP/1.1 ne connaissent pas ce code de retour. De +plus, la plupart des navigateurs se comportent déjà avec le code 302 comme ils +devraient le faire avec le 303. Donc, dans le but de laisser le choix à +l'utilisateur, la version 1.2.5 apporte deux nouvelles commandes visant à +remplacer 'errorloc' : 'errorloc302' et 'errorloc303'. + +Leur usage non ambigü est recommandé à la place de la commande 'errorloc' (qui +utilise toujours 302). Dans le doute, préférez l'utilisation de 'errorloc303' +dès que vous savez que vos clients supportent le code de retour HTTP 303. + 4.7) Changement des valeurs par défaut -------------------------------------- Dans la version 1.1.22 est apparue la notion de valeurs par défaut, ce qui évite diff --git a/haproxy.c b/haproxy.c index 1445d1b3b1..c5c29177cf 100644 --- a/haproxy.c +++ b/haproxy.c @@ -30,6 +30,7 @@ * and client suddenly disconnects. The server *should* switch to SHUT_WR, but * still handle HTTP headers. * - remove MAX_NEWHDR + * - cut this huge file into several ones * */ @@ -63,8 +64,8 @@ #include "include/appsession.h" -#define HAPROXY_VERSION "1.2.4" -#define HAPROXY_DATE "2005/01/22" +#define HAPROXY_VERSION "1.2.5" +#define HAPROXY_DATE "2005/04/24" /* this is for libc5 for example */ #ifndef TCP_NODELAY @@ -680,6 +681,13 @@ const char *HTTP_302 = "Connection: close\r\n" "Location: "; /* not terminated since it will be concatenated with the URL */ +/* same as 302 except that the browser MUST retry with the GET method */ +const char *HTTP_303 = + "HTTP/1.0 303 See Other\r\n" + "Cache-Control: no-cache\r\n" + "Connection: close\r\n" + "Location: "; /* not terminated since it will be concatenated with the URL */ + const char *HTTP_400 = "HTTP/1.0 400 Bad request\r\n" "Cache-Control: no-cache\r\n" @@ -2695,7 +2703,8 @@ int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) { unsigned char hex1, hex2; str++; - hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0'; + hex1 = toupper(*str++) - '0'; + hex2 = toupper(*str++) - '0'; if (hex1 > 9) hex1 -= 'A' - '9' - 1; if (hex2 > 9) hex2 -= 'A' - '9' - 1; @@ -2711,6 +2720,43 @@ int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) { return dst - old_dst; } +static int ishex(char s) +{ + return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f'); +} + +/* returns NULL if the replacement string is valid, or the pointer to the first error */ +char *check_replace_string(char *str) +{ + char *err = NULL; + while (*str) { + if (*str == '\\') { + err = str; /* in case of a backslash, we return the pointer to it */ + str++; + if (!*str) + return err; + else if (isdigit((int)*str)) + err = NULL; + else if (*str == 'x') { + str++; + if (!ishex(*str)) + return err; + str++; + if (!ishex(*str)) + return err; + err = NULL; + } + else { + Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str); + err = NULL; + } + } + str++; + } + return err; +} + + /* * manages the client FSM and its socket. BTW, it also tries to handle the @@ -4801,7 +4847,7 @@ void select_loop() { /* let's restore fdset state */ readnotnull = 0; writenotnull = 0; - for (i = 0; i < (global.maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) { + for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) { readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0; writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0; } @@ -5088,9 +5134,17 @@ void sig_term(int sig) { signal(sig, SIG_DFL); } -void chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) { +/* returns the pointer to an error in the replacement string, or NULL if OK */ +char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) { struct hdr_exp *exp; + if (replace != NULL) { + char *err; + err = check_replace_string(replace); + if (err) + return err; + } + while (*head != NULL) head = &(*head)->next; @@ -5100,6 +5154,8 @@ void chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace exp->replace = replace; exp->action = action; *head = exp; + + return NULL; } @@ -5261,6 +5317,7 @@ void init_default_instance() { int cfg_parse_listen(char *file, int linenum, char **args) { static struct proxy *curproxy = NULL; struct server *newsrv = NULL; + char *err; int rc; if (!strcmp(args[0], "listen")) { /* new proxy */ @@ -5962,7 +6019,12 @@ int cfg_parse_listen(char *file, int linenum, char **args) { return -1; } - chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2])); + err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2])); + if (err) { + Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n", + file, linenum, *err); + return -1; + } } else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */ regex_t *preg; @@ -6063,7 +6125,12 @@ int cfg_parse_listen(char *file, int linenum, char **args) { return -1; } - chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2])); + err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2])); + if (err) { + Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n", + file, linenum, *err); + return -1; + } } else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */ regex_t *preg; @@ -6178,7 +6245,12 @@ int cfg_parse_listen(char *file, int linenum, char **args) { return -1; } - chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2])); + err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2])); + if (err) { + Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n", + file, linenum, *err); + return -1; + } } else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */ regex_t *preg; @@ -6198,7 +6270,12 @@ int cfg_parse_listen(char *file, int linenum, char **args) { return -1; } - chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2])); + err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2])); + if (err) { + Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n", + file, linenum, *err); + return -1; + } } else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */ regex_t *preg; @@ -6218,7 +6295,12 @@ int cfg_parse_listen(char *file, int linenum, char **args) { return -1; } - chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2])); + err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2])); + if (err) { + Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n", + file, linenum, *err); + return -1; + } } else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */ regex_t *preg; @@ -6239,7 +6321,12 @@ int cfg_parse_listen(char *file, int linenum, char **args) { return -1; } - chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2])); + err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2])); + if (err) { + Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n", + file, linenum, *err); + return -1; + } } else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */ regex_t *preg; @@ -6259,7 +6346,12 @@ int cfg_parse_listen(char *file, int linenum, char **args) { return -1; } - chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2])); + err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2])); + if (err) { + Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n", + file, linenum, *err); + return -1; + } } else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */ regex_t *preg; @@ -6279,7 +6371,12 @@ int cfg_parse_listen(char *file, int linenum, char **args) { return -1; } - chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2])); + err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2])); + if (err) { + Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n", + file, linenum, *err); + return -1; + } } else if (!strcmp(args[0], "rspadd")) { /* add response header */ if (curproxy == &defproxy) { @@ -6299,8 +6396,10 @@ int cfg_parse_listen(char *file, int linenum, char **args) { curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]); } - else if (!strcmp(args[0], "errorloc")) { /* error location */ - int errnum; + else if (!strcmp(args[0], "errorloc") || + !strcmp(args[0], "errorloc302") || + !strcmp(args[0], "errorloc303")) { /* error location */ + int errnum, errlen; char *err; // if (curproxy == &defproxy) { @@ -6314,8 +6413,13 @@ int cfg_parse_listen(char *file, int linenum, char **args) { } errnum = atol(args[1]); - err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5); - sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]); + if (!strcmp(args[0], "errorloc303")) { + err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5); + errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]); + } else { + err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5); + errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]); + } if (errnum == 400) { if (curproxy->errmsg.msg400) { @@ -6323,7 +6427,7 @@ int cfg_parse_listen(char *file, int linenum, char **args) { free(curproxy->errmsg.msg400); } curproxy->errmsg.msg400 = err; - curproxy->errmsg.len400 = strlen(err); + curproxy->errmsg.len400 = errlen; } else if (errnum == 403) { if (curproxy->errmsg.msg403) { @@ -6331,7 +6435,7 @@ int cfg_parse_listen(char *file, int linenum, char **args) { free(curproxy->errmsg.msg403); } curproxy->errmsg.msg403 = err; - curproxy->errmsg.len403 = strlen(err); + curproxy->errmsg.len403 = errlen; } else if (errnum == 408) { if (curproxy->errmsg.msg408) { @@ -6339,7 +6443,7 @@ int cfg_parse_listen(char *file, int linenum, char **args) { free(curproxy->errmsg.msg408); } curproxy->errmsg.msg408 = err; - curproxy->errmsg.len408 = strlen(err); + curproxy->errmsg.len408 = errlen; } else if (errnum == 500) { if (curproxy->errmsg.msg500) { @@ -6347,7 +6451,7 @@ int cfg_parse_listen(char *file, int linenum, char **args) { free(curproxy->errmsg.msg500); } curproxy->errmsg.msg500 = err; - curproxy->errmsg.len500 = strlen(err); + curproxy->errmsg.len500 = errlen; } else if (errnum == 502) { if (curproxy->errmsg.msg502) { @@ -6355,7 +6459,7 @@ int cfg_parse_listen(char *file, int linenum, char **args) { free(curproxy->errmsg.msg502); } curproxy->errmsg.msg502 = err; - curproxy->errmsg.len502 = strlen(err); + curproxy->errmsg.len502 = errlen; } else if (errnum == 503) { if (curproxy->errmsg.msg503) { @@ -6363,7 +6467,7 @@ int cfg_parse_listen(char *file, int linenum, char **args) { free(curproxy->errmsg.msg503); } curproxy->errmsg.msg503 = err; - curproxy->errmsg.len503 = strlen(err); + curproxy->errmsg.len503 = errlen; } else if (errnum == 504) { if (curproxy->errmsg.msg504) { @@ -6371,7 +6475,7 @@ int cfg_parse_listen(char *file, int linenum, char **args) { free(curproxy->errmsg.msg504); } curproxy->errmsg.msg504 = err; - curproxy->errmsg.len504 = strlen(err); + curproxy->errmsg.len504 = errlen; } else { Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum); @@ -6443,14 +6547,21 @@ int readcfgfile(char *file) { *line = '\t'; skip = 1; } - else if (line[1] == 'x' && (line + 3 < end )) { - unsigned char hex1, hex2; - hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0'; - if (hex1 > 9) hex1 -= 'A' - '9' - 1; - if (hex2 > 9) hex2 -= 'A' - '9' - 1; - *line = (hex1<<4) + hex2; - skip = 3; - } + else if (line[1] == 'x') { + if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) { + unsigned char hex1, hex2; + hex1 = toupper(line[2]) - '0'; + hex2 = toupper(line[3]) - '0'; + if (hex1 > 9) hex1 -= 'A' - '9' - 1; + if (hex2 > 9) hex2 -= 'A' - '9' - 1; + *line = (hex1<<4) + hex2; + skip = 3; + } + else { + Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]); + return -1; + } + } if (skip) { memmove(line + 1, line + 1 + skip, end - (line + skip + 1)); end -= skip;