]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
* released 1.2.5-pre2 v1.2.5-pre2
authorwilly tarreau <willy@wtap.(none)>
Sun, 18 Dec 2005 00:08:26 +0000 (01:08 +0100)
committerwilly tarreau <willy@wtap.(none)>
Sun, 18 Dec 2005 00:08:26 +0000 (01:08 +0100)
* 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.

CHANGELOG
doc/haproxy-en.txt
doc/haproxy-fr.txt
haproxy.c

index df96dd6d8559b09053ff17317e8dc4fc09a6162c..f0af36f44bcbe31f36c588c31cedb255892f3f76 100644 (file)
--- 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
index ab14dcf1e4482fbdf93ff84377d05cdeea8188d7..65ebb96d6e16146c650ad21ef5ab8e9eb923c80e 100644 (file)
@@ -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
index 1db2bc4674535243f258ccda54bd573a5ffe4ff0..109c45cec884c5dda951f546ed8b7871e02c405b 100644 (file)
@@ -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
index 1445d1b3b1cfcde3785200fada5861103eee8bd1..c5c29177cf188b139a8e97abbc179a707ff9126b 100644 (file)
--- 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 <str> 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;