mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 07:37:02 +02:00
[MEDIUM] errorfile: use a local file to feed error messages
It is now possible to read error messages from local files, using the 'errorfile' keyword. Those files are read during parsing, so there's no I/O involved. They make it possible to return custom error messages with custom status and headers.
This commit is contained in:
parent
1ad7c6dd85
commit
3f49b30284
@ -2311,8 +2311,13 @@ Some situations can make haproxy return an HTTP error code to the client :
|
|||||||
|
|
||||||
A succint error message taken from the RFC accompanies these return codes.
|
A succint error message taken from the RFC accompanies these return codes.
|
||||||
But depending on the clients knowledge, it may be better to return custom, user
|
But depending on the clients knowledge, it may be better to return custom, user
|
||||||
friendly, error pages. This is made possible through the use of the 'errorloc'
|
friendly, error pages. This is made possible in two ways, one involving a
|
||||||
command :
|
redirection to a known server, and another one consisting in returning a local
|
||||||
|
file.
|
||||||
|
|
||||||
|
4.6.1) Relocation
|
||||||
|
-----------------
|
||||||
|
An error relocation is achieved using the 'errorloc' command :
|
||||||
|
|
||||||
errorloc <HTTP_code> <location>
|
errorloc <HTTP_code> <location>
|
||||||
|
|
||||||
@ -2344,6 +2349,33 @@ bring two new keywords to replace 'errorloc' : 'errorloc302' and 'errorloc303'.
|
|||||||
They are preffered over errorloc (which still does 302). Consider using
|
They are preffered over errorloc (which still does 302). Consider using
|
||||||
errorloc303 everytime you know that your clients support HTTP 303 responses..
|
errorloc303 everytime you know that your clients support HTTP 303 responses..
|
||||||
|
|
||||||
|
4.6.2) Local files
|
||||||
|
------------------
|
||||||
|
Sometimes, it is desirable to change the returned error without resorting to
|
||||||
|
redirections. The second method consists in loading local files during startup
|
||||||
|
and send them as pure HTTP content upon error. This is what the 'errorfile'
|
||||||
|
keyword does.
|
||||||
|
|
||||||
|
Warning, there are traps to consider :
|
||||||
|
- The files are loaded while parsing configuration, before doing a chroot().
|
||||||
|
Thus, they are relative to the real filesystem. For this reason, it is
|
||||||
|
recommended to pass an absolute path to those files.
|
||||||
|
|
||||||
|
- The contents of those files is not HTML, but real HTTP protocol with
|
||||||
|
possible HTML body. So the first line and headers are mandatory. Ideally,
|
||||||
|
every line in the HTTP part should end with CR-LF for maximum compatibility.
|
||||||
|
|
||||||
|
- The response is limited to the buffer size (BUSIZE), generally 8 or 16 kB.
|
||||||
|
|
||||||
|
- The response should not include references to the local server, in order to
|
||||||
|
avoid infinite loops on the browser in case of local failure.
|
||||||
|
|
||||||
|
Example :
|
||||||
|
---------
|
||||||
|
errorfile 400 /etc/haproxy/errorfiles/400badreq.http
|
||||||
|
errorfile 403 /etc/haproxy/errorfiles/403forbid.http
|
||||||
|
errorfile 503 /etc/haproxy/errorfiles/503sorry.http
|
||||||
|
|
||||||
|
|
||||||
4.7) Modifying default values
|
4.7) Modifying default values
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
@ -2395,7 +2395,13 @@ Certaines situations conduisent
|
|||||||
|
|
||||||
Un message d'erreur succint tiré de la RFC accompagne ces codes de retour.
|
Un message d'erreur succint tiré de la RFC accompagne ces codes de retour.
|
||||||
Cependant, en fonction du type de clientèle, on peut préférer retourner des
|
Cependant, en fonction du type de clientèle, on peut préférer retourner des
|
||||||
pages personnalisées. Ceci est possible par le biais de la commande "errorloc":
|
pages personnalisées. Ceci est possible de deux manières, l'une reposant sur
|
||||||
|
une redirection vers un serveur connu, et l'autre consistant à retourner un
|
||||||
|
fichier local.
|
||||||
|
|
||||||
|
4.6.1) Redirection
|
||||||
|
------------------
|
||||||
|
Une redirection d'erreur est assurée par le biais de la commande "errorloc" :
|
||||||
|
|
||||||
errorloc <code_HTTP> <location>
|
errorloc <code_HTTP> <location>
|
||||||
|
|
||||||
@ -2431,6 +2437,38 @@ Leur usage non ambig
|
|||||||
utilise toujours 302). Dans le doute, préférez l'utilisation de 'errorloc303'
|
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.
|
dès que vous savez que vos clients supportent le code de retour HTTP 303.
|
||||||
|
|
||||||
|
4.6.2) Fichiers locaux
|
||||||
|
----------------------
|
||||||
|
Parfois il est souhaitable de changer l'erreur retournée sans recourir à des
|
||||||
|
redirections. La seconde méthode consiste à charger des fichiers locaux lors
|
||||||
|
du démarrage et à les envoyer en guise de pur contenu HTTP en cas d'erreur.
|
||||||
|
C'est ce que fait le mot clé 'errorfile'.
|
||||||
|
|
||||||
|
Attention, il y a des pièges à prendre en compte :
|
||||||
|
- les fichiers sont chargés durant l'analyse de la configuration, avant de
|
||||||
|
faire le chroot(). Donc ils sont relatifs au système de fichiers réel. Pour
|
||||||
|
cette raison, il est recommandé de toujours passer un chemin absolu vers ces
|
||||||
|
fichiers.
|
||||||
|
|
||||||
|
- le contenu de ces fichiers n'est pas du HTML mais vraiment du protocole HTTP
|
||||||
|
avec potentiellement un corps HTML. Donc la première ligne et les en-têtes
|
||||||
|
sont obligatoires. Idéalement, chaque ligne dans la partie HTTP devrait se
|
||||||
|
terminer par un CR-LF pour un maximum de compatibilité.
|
||||||
|
|
||||||
|
- les réponses sont limitées à une taille de buffer (BUFSIZE), généralement 8
|
||||||
|
ou 16 ko.
|
||||||
|
|
||||||
|
- les réponses ne devraient pas inclure de références aux serveurs locaux,
|
||||||
|
afin de ne pas risquer de créer des boucles infinies sur le navigateur dans
|
||||||
|
le cas d'une panne locale.
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
---------
|
||||||
|
errorfile 400 /etc/haproxy/errorfiles/400badreq.http
|
||||||
|
errorfile 403 /etc/haproxy/errorfiles/403forbid.http
|
||||||
|
errorfile 503 /etc/haproxy/errorfiles/503sorry.http
|
||||||
|
|
||||||
|
|
||||||
4.7) Changement des valeurs par défaut
|
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
|
Dans la version 1.1.22 est apparue la notion de valeurs par défaut, ce qui
|
||||||
|
9
examples/errorfiles/400.http
Normal file
9
examples/errorfiles/400.http
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
HTTP/1.0 400 Bad request
|
||||||
|
Cache-Control: no-cache
|
||||||
|
Connection: close
|
||||||
|
Content-Type: text/html
|
||||||
|
|
||||||
|
<html><body><h1>400 Bad request</h1>
|
||||||
|
Your browser sent an invalid request.
|
||||||
|
</body></html>
|
||||||
|
|
9
examples/errorfiles/403.http
Normal file
9
examples/errorfiles/403.http
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
HTTP/1.0 403 Forbidden
|
||||||
|
Cache-Control: no-cache
|
||||||
|
Connection: close
|
||||||
|
Content-Type: text/html
|
||||||
|
|
||||||
|
<html><body><h1>403 Forbidden</h1>
|
||||||
|
Request forbidden by administrative rules.
|
||||||
|
</body></html>
|
||||||
|
|
9
examples/errorfiles/408.http
Normal file
9
examples/errorfiles/408.http
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
HTTP/1.0 408 Request Time-out
|
||||||
|
Cache-Control: no-cache
|
||||||
|
Connection: close
|
||||||
|
Content-Type: text/html
|
||||||
|
|
||||||
|
<html><body><h1>408 Request Time-out</h1>
|
||||||
|
Your browser didn't send a complete request in time.
|
||||||
|
</body></html>
|
||||||
|
|
9
examples/errorfiles/500.http
Normal file
9
examples/errorfiles/500.http
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
HTTP/1.0 500 Server Error
|
||||||
|
Cache-Control: no-cache
|
||||||
|
Connection: close
|
||||||
|
Content-Type: text/html
|
||||||
|
|
||||||
|
<html><body><h1>500 Server Error</h1>
|
||||||
|
An internal server error occured.
|
||||||
|
</body></html>
|
||||||
|
|
9
examples/errorfiles/502.http
Normal file
9
examples/errorfiles/502.http
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
HTTP/1.0 502 Bad Gateway
|
||||||
|
Cache-Control: no-cache
|
||||||
|
Connection: close
|
||||||
|
Content-Type: text/html
|
||||||
|
|
||||||
|
<html><body><h1>502 Bad Gateway</h1>
|
||||||
|
The server returned an invalid or incomplete response.
|
||||||
|
</body></html>
|
||||||
|
|
9
examples/errorfiles/503.http
Normal file
9
examples/errorfiles/503.http
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
HTTP/1.0 503 Service Unavailable
|
||||||
|
Cache-Control: no-cache
|
||||||
|
Connection: close
|
||||||
|
Content-Type: text/html
|
||||||
|
|
||||||
|
<html><body><h1>503 Service Unavailable</h1>
|
||||||
|
No server is available to handle this request.
|
||||||
|
</body></html>
|
||||||
|
|
9
examples/errorfiles/504.http
Normal file
9
examples/errorfiles/504.http
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
HTTP/1.0 504 Gateway Time-out
|
||||||
|
Cache-Control: no-cache
|
||||||
|
Connection: close
|
||||||
|
Content-Type: text/html
|
||||||
|
|
||||||
|
<html><body><h1>504 Gateway Time-out</h1>
|
||||||
|
The server didn't respond in time.
|
||||||
|
</body></html>
|
||||||
|
|
9
examples/errorfiles/README
Normal file
9
examples/errorfiles/README
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
These files are default error files that can be customized
|
||||||
|
if necessary. They are complete HTTP responses, so that
|
||||||
|
everything is possible, including using redirects or setting
|
||||||
|
special headers.
|
||||||
|
|
||||||
|
They can be used with the 'errorfile' keyword like this :
|
||||||
|
|
||||||
|
errorfile 503 /etc/haproxy/errors/503.http
|
||||||
|
|
@ -76,4 +76,5 @@ listen appli5-backup 0.0.0.0:10005
|
|||||||
rspidel ^Set-cookie:\ IP= # do not let this cookie tell our internal IP address
|
rspidel ^Set-cookie:\ IP= # do not let this cookie tell our internal IP address
|
||||||
|
|
||||||
errorloc 502 http://192.168.114.58/error502.html
|
errorloc 502 http://192.168.114.58/error502.html
|
||||||
|
errorfile 503 /etc/haproxy/errors/503.http
|
||||||
|
|
||||||
|
@ -18,6 +18,10 @@
|
|||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <common/cfgparse.h>
|
#include <common/cfgparse.h>
|
||||||
#include <common/config.h>
|
#include <common/config.h>
|
||||||
@ -2093,11 +2097,6 @@ int cfg_parse_listen(const char *file, int linenum, char **args)
|
|||||||
int errnum, errlen;
|
int errnum, errlen;
|
||||||
char *err;
|
char *err;
|
||||||
|
|
||||||
// if (curproxy == &defproxy) {
|
|
||||||
// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
|
|
||||||
// return -1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
|
if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -2131,6 +2130,64 @@ int cfg_parse_listen(const char *file, int linenum, char **args)
|
|||||||
free(err);
|
free(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(args[0], "errorfile")) { /* error message from a file */
|
||||||
|
int errnum, errlen, fd;
|
||||||
|
char *err;
|
||||||
|
struct stat stat;
|
||||||
|
|
||||||
|
if (warnifnotcap(curproxy, PR_CAP_FE | PR_CAP_BE, file, linenum, args[0], NULL))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (*(args[2]) == 0) {
|
||||||
|
Alert("parsing [%s:%d] : <%s> expects <status_code> and <file> as arguments.\n", file, linenum);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = open(args[2], O_RDONLY);
|
||||||
|
if ((fd < 0) || (fstat(fd, &stat) < 0)) {
|
||||||
|
Alert("parsing [%s:%d] : error opening file <%s> for custom error message <%s>.\n",
|
||||||
|
file, linenum, args[2], args[1]);
|
||||||
|
if (fd >= 0)
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat.st_size <= BUFSIZE) {
|
||||||
|
errlen = stat.st_size;
|
||||||
|
} else {
|
||||||
|
Warning("parsing [%s:%d] : custom error message file <%s> larger than %d bytes. Truncating.\n",
|
||||||
|
file, linenum, args[2], BUFSIZE);
|
||||||
|
errlen = BUFSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = malloc(errlen); /* malloc() must succeed during parsing */
|
||||||
|
errnum = read(fd, err, errlen);
|
||||||
|
if (errnum != errlen) {
|
||||||
|
Alert("parsing [%s:%d] : error reading file <%s> for custom error message <%s>.\n",
|
||||||
|
file, linenum, args[2], args[1]);
|
||||||
|
close(fd);
|
||||||
|
free(err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
errnum = atol(args[1]);
|
||||||
|
for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
|
||||||
|
if (http_err_codes[rc] == errnum) {
|
||||||
|
if (curproxy->errmsg[rc].str)
|
||||||
|
free(curproxy->errmsg[rc].str);
|
||||||
|
curproxy->errmsg[rc].str = err;
|
||||||
|
curproxy->errmsg[rc].len = errlen;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc >= HTTP_ERR_SIZE) {
|
||||||
|
Warning("parsing [%s:%d] : status code %d not handled, error customization will be ignored.\n",
|
||||||
|
file, linenum, errnum);
|
||||||
|
free(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
|
Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
|
||||||
return -1;
|
return -1;
|
||||||
|
Loading…
Reference in New Issue
Block a user