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>      = optionnal action args

    exemples:

        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 ?
