haproxy/doc/design-thoughts/config-language.txt

263 lines
9.3 KiB
Plaintext

Prévoir des commandes en plusieurs mots clés.
Par exemple :
timeout connection XXX
connection scale XXX
On doit aussi accepter les préfixes :
tim co XXX
co sca XXX
Prévoir de ranger les combinaisons dans un tableau. On doit même
pouvoir effectuer un mapping simplifiant le parseur.
Pour les filtres :
<direction> <where> <what> <operator> <pattern> <action> [ <args>* ]
<direction> = [ req | rsp ]
<where> = [ in | out ]
<what> = [ line | LINE | METH | URI | h(hdr) | H(hdr) | c(cookie) | C(cookie) ]
<operator> = [ == | =~ | =* | =^ | =/ | != | !~ | !* | !^ | !/ ]
<pattern> = "<string>"
<action> = [ allow | permit | deny | delete | replace | switch | add | set | redir ]
<args> = optional action args
examples:
req in URI =^ "/images" switch images
req in h(host) =* ".mydomain.com" switch mydomain
req in h(host) =~ "localhost(.*)" replace "www\1"
alternative :
<direction> <where> <action> [not] <what> [<operator> <pattern> [ <args>* ]]
req in switch URI =^ "/images" images
req in switch h(host) =* ".mydomain.com" mydomain
req in replace h(host) =~ "localhost(.*)" "www\1"
req in delete h(Connection)
req in deny not line =~ "((GET|HEAD|POST|OPTIONS) /)|(OPTIONS *)"
req out set h(Connection) "close"
req out add line "Server: truc"
<direction> <action> <where> [not] <what> [<operator> <pattern> [ <args>* ]] ';' <action2> <what2>
req in switch URI =^ "/images/" images ; replace "/"
req in switch h(host) =* ".mydomain.com" mydomain
req in replace h(host) =~ "localhost(.*)" "www\1"
req in delete h(Connection)
req in deny not line =~ "((GET|HEAD|POST|OPTIONS) /)|(OPTIONS *)"
req out set h(Connection) "close"
req out add line == "Server: truc"
Extension avec des ACL :
req in acl(meth_valid) METH =~ "(GET|POST|HEAD|OPTIONS)"
req in acl(meth_options) METH == "OPTIONS"
req in acl(uri_slash) URI =^ "/"
req in acl(uri_star) URI == "*"
req in deny acl !(meth_options && uri_star || meth_valid && uri_slash)
Peut-être plus simplement :
acl meth_valid METH =~ "(GET|POST|HEAD|OPTIONS)"
acl meth_options METH == "OPTIONS"
acl uri_slash URI =^ "/"
acl uri_star URI == "*"
req in deny not acl(meth_options uri_star, meth_valid uri_slash)
req in switch URI =^ "/images/" images ; replace "/"
req in switch h(host) =* ".mydomain.com" mydomain
req in replace h(host) =~ "localhost(.*)" "www\1"
req in delete h(Connection)
req in deny not line =~ "((GET|HEAD|POST|OPTIONS) /)|(OPTIONS *)"
req out set h(Connection) "close"
req out add line == "Server: truc"
Prévoir le cas du "if" pour exécuter plusieurs actions :
req in if URI =^ "/images/" then replace "/" ; switch images
Utiliser les noms en majuscules/minuscules pour indiquer si on veut prendre
en compte la casse ou non :
if uri =^ "/watch/" setbe watch rebase "/watch/" "/"
if uri =* ".jpg" setbe images
if uri =~ ".*dll.*" deny
if HOST =* ".mydomain.com" setbe mydomain
etc...
Another solution would be to have a dedicated keyword to URI remapping. It
would both rewrite the URI and optionally switch to another backend.
uriremap "/watch/" "/" watch
uriremap "/chat/" "/" chat
uriremap "/event/" "/event/" event
Or better :
uriremap "/watch/" watch "/"
uriremap "/chat/" chat "/"
uriremap "/event/" event
For the URI, using a regex is sometimes useful (eg: providing a set of possible prefixes.
Sinon, peut-être que le "switch" peut prendre un paramètre de mapping pour la partie matchée :
req in switch URI =^ "/images/" images:"/"
2007/03/31 - Besoins plus précis.
1) aucune extension de branchement ou autre dans les "listen", c'est trop complexe.
Distinguer les données entrantes (in) et sortantes (out).
Le frontend ne voit que les requetes entrantes et les réponses sortantes.
Le backend voir les requêtes in/out et les réponses in/out.
Le frontend permet les branchements d'ensembles de filtres de requêtes vers
d'autres. Le frontend et les ensembles de filtres de requêtes peuvent brancher
vers un backend.
-----------+--------+----------+----------+---------+----------+
\ Where | | | | | |
\______ | Listen | Frontend | ReqRules | Backend | RspRules |
\| | | | | |
Capability | | | | | |
-----------+--------+----------+----------+---------+----------+
Frontend | X | X | | | |
-----------+--------+----------+----------+---------+----------+
FiltReqIn | X | X | X | X | |
-----------+--------+----------+----------+---------+----------+
JumpFiltReq| X | X | X | | | \
-----------+--------+----------+----------+---------+----------+ > = ReqJump
SetBackend | X | X | X | | | /
-----------+--------+----------+----------+---------+----------+
FiltReqOut | | | | X | |
-----------+--------+----------+----------+---------+----------+
FiltRspIn | X | | | X | X |
-----------+--------+----------+----------+---------+----------+
JumpFiltRsp| | | | X | X |
-----------+--------+----------+----------+---------+----------+
FiltRspOut | | X | | X | X |
-----------+--------+----------+----------+---------+----------+
Backend | X | | | X | |
-----------+--------+----------+----------+---------+----------+
En conclusion
-------------
Il y a au moins besoin de distinguer 8 fonctionnalités de base :
- capacité à recevoir des connexions (frontend)
- capacité à filtrer les requêtes entrantes
- capacité à brancher vers un backend ou un ensemble de règles de requêtes
- capacité à filtrer les requêtes sortantes
- capacité à filtrer les réponses entrantes
- capacité à brancher vers un autre ensemble de règles de réponses
- capacité à filtrer la réponse sortante
- capacité à gérer des serveurs (backend)
Remarque
--------
- on a souvent besoin de pouvoir appliquer un petit traitement sur un ensemble
host/uri/autre. Le petit traitement peut consister en quelques filtres ainsi
qu'une réécriture du couple (host,uri).
Proposition : ACL
Syntaxe :
---------
acl <name> <what> <operator> <value> ...
Ceci créera une acl référencée sous le nom <name> qui sera validée si
l'application d'au moins une des valeurs <value> avec l'opérateur <operator>
sur le sujet <what> est validée.
Opérateurs :
------------
Toujours 2 caractères :
[=!][~=*^%/.]
Premier caractère :
'=' : OK si test valide
'!' : OK si test échoué.
Second caractère :
'~' : compare avec une regex
'=' : compare chaîne à chaîne
'*' : compare la fin de la chaîne (ex: =* ".mydomain.com")
'^' : compare le début de la chaîne (ex: =^ "/images/")
'%' : recherche une sous-chaîne
'/' : compare avec un mot entier en acceptant le '/' comme délimiteur
'.' : compare avec un mot entier en acceptant el '.' comme délimiteur
Ensuite on exécute une action de manière conditionnelle si l'ensemble des ACLs
mentionnées sont validées (ou invalidées pour celles précédées d'un "!") :
<what> <where> <action> on [!]<aclname> ...
Exemple :
---------
acl www_pub host =. www www01 dev preprod
acl imghost host =. images
acl imgdir uri =/ img
acl imagedir uri =/ images
acl msie h(user-agent) =% "MSIE"
set_host "images" on www_pub imgdir
remap_uri "/img" "/" on www_pub imgdir
remap_uri "/images" "/" on www_pub imagedir
setbe images on imghost
reqdel "Cookie" on all
Actions possibles :
req {in|out} {append|delete|rem|add|set|rep|mapuri|rewrite|reqline|deny|allow|setbe|tarpit}
resp {in|out} {append|delete|rem|add|set|rep|maploc|rewrite|stsline|deny|allow}
req in append <line>
req in delete <line_regex>
req in rem <header>
req in add <header> <new_value>
req in set <header> <new_value>
req in rep <header> <old_value> <new_value>
req in mapuri <old_uri_prefix> <new_uri_prefix>
req in rewrite <old_uri_regex> <new_uri>
req in reqline <old_req_regex> <new_req>
req in deny
req in allow
req in tarpit
req in setbe <backend>
resp out maploc <old_location_prefix> <new_loc_prefix>
resp out stsline <old_sts_regex> <new_sts_regex>
Les chaînes doivent être délimitées par un même caractère au début et à la fin,
qui doit être échappé s'il est présent dans la chaîne. Tout ce qui se trouve
entre le caractère de fin et les premiers espace est considéré comme des
options passées au traitement. Par exemple :
req in rep host /www/i /www/
req in rep connection /keep-alive/i "close"
Il serait pratique de pouvoir effectuer un remap en même temps qu'un setbe.
Captures: les séparer en in/out. Les rendre conditionnelles ?