* 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.
This commit is contained in:
willy tarreau 2005-12-18 01:08:26 +01:00
parent 598da41537
commit c1f4753d60
4 changed files with 188 additions and 36 deletions

View File

@ -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

View 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

View 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

161
haproxy.c
View File

@ -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]);
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);
sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
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 )) {
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';
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;