Un reverse proxy bien complet…
J’ai un client qui a un client qui a un (in|ex)tranet. Il veut qu’on puisse y accéder depuis partout dehors, et il veux que ce soit simple pour les gens qui y accèdent.
J’ai donc exclu d’emblée un proxy basique, puisqu’il faudrait que les “gens” aillent changer la configuration de leur navigateur selon s’il veulent accéder à l’extranet, ou au reste du net (parce que, non, j’allais pas faire un proxy ouvert à tous vents, sisi, faut que ce soit simple, donc, pas de login/pass).
Donc, fort de ces informations, je m’en vais faire un reverse proxy avec
apache. Il y a tout ce qu’il faut, les directives ProxyPass,
ProxyPassReverse et même ProxyPassReverseCookieDomain me plaisent
beaucoup, et donc je tente :
<VirtualHost *:80> ServerName truc.com ProxyPass / http://extranet.com/ ProxyPassReverse / http://extranet.com/ ProxyPassReverseCookieDomain extranet.com truc.com </VirtualHost>
Ça marche impeccable pour la page d’accueil, et là, oh horreur, le formulaire
de login contient <form action="http://extranet.com/login.cgi"> et donc, dès
la première page, ça ne va plus marcher.
Après quelques petites recherches, je tombe sur un
mod_proxy_html qui me
semble encore une fois être tout à fait ce dont j’ai besoin… Je transforme ma
configuration, d’abord en en faisant qu’a ma tête (ce qui ne marche pas) puis
en suivant la doc (ce qui marche) et j’arrive à :
LoadFile /usr/local/lib/libxml2.so LoadModule proxy_html_module libexec/apache22/mod_proxy_html.so ProxyRequests off <VirtualHost *:80> ServerName truc.com ProxyPass / http://extranet.com/ ProxyHTMLURLMap http://extranet.com/ / <Location /> ProxyPassReverse / SetOutputFilter proxy-html ProxyPassReverseCookieDomain extranet.com truc.com ProxyHTMLURLMap / / RequestHeader unset Accept-Encoding </Location> </VirtualHost>
Et le formulaire de la page de démarrage est modifié en @<form action=”/login.cgi”>@. Miracle, joie, bonheur, tout ça.
Et là, je regarde de plus près, et une partie de la page a été réécrite (mais
elle s’affiche correctement), le <!DOCTYPE ...> en haut de la page a été
viré. Je retourne sur le site de mon mod_proxy_html et je découvre dans la
faq que ça va virer le dtd ou en mettre un, réécrire le html, tout convertir
en utf-8. Déception, haine, tout ça.
Si ça ne fonctionne pas comme il faut, j’en serais réduit à regarder comment
faire ça avec un OutputFilter et @mod_perl@…
Update
Alors, bon, dans le site, y’a du javascript partout, alors, mod_proxy_html
il roxe beaucoup moins déjà… J’ai donc lu un peu de doc sur mod_perl et un
des exemples qui fait un reverse ligne par ligne m’a convaincu, ça donne donc
:
LoadModule perl_module libexec/apache22/mod_perl.so PerlRequire /usr/local/etc/apache22/perl/inc.pl <VirtualHost *:80> ServerName truc.com ProxyPass / http://extranet.com/ <Location /> ProxyPassReverse / SetHandler modperl PerlOutputFilterHandler ReverseProxy </Location> </VirtualHost>
et
package ReverseProxy; use strict; use warnings; use Apache2::RequestRec (); use Apache2::RequestIO (); use Apache2::Const -compile => qw(OK); use base qw(Apache2::Filter); use Apache2::Const -compile => qw(OK); use constant BUFF_LEN => 100; sub transform($) { my $s = shift; $s =~ s/extranet\.com/truc.com/og; return $s; } sub handler : FilterRequestHandler { my $f = shift; my $leftover = $f->ctx; while ( $f->read( my $buffer, BUFF_LEN ) ) { $buffer = $leftover . $buffer if defined $leftover; $leftover = undef; while ( $buffer =~ /([^\r\n]*)([\r\n]*)/g ) { $leftover = $1, last unless $2; $f->print( transform($1), $2 ); } } if ( defined($leftover) ) { if ( $f->seen_eos ) { $f->print( transform($leftover) ); $f->ctx(undef); } else { $f->ctx($leftover); } } else { $f->ctx(undef); } return Apache2::Const::OK; } 1;
Et miracle, ça fonctionne tout comme il faut… (Pour l’instant…)
Update, le retours
Alors, dans mon exemple, extranet.com et truc.com ne font pas la même taille, et ça pose problème, parce que le navigateur, va demander la page, la récupérer, mais elle sera plus petite que l’originale, et lors d’une requête ultérieure, avec toutes les en-têtes qui vont bien pour ne pas réenvoyer les pages pour rien, le serveur va juste répondre wé, c’est bon, elle a pas changé, et elle fait telle taille, sauf que, la taille que le navigateur il a déjà récupérée, elle est plus petite, et comme pour lui, la taille compte, il va jouer au con, et demander les X octets manquant de la page.
Pour une page web, il va résulter que un petit “ml<\n” se retrouvera ajouté a la fin (dans mon exemple ou ça fait 4 caractères de moins), dans un javascript, ça va être beaucoup plus problèmatique, parce que on va genre récupérer “}\n}\n”, et bien sur, ça ne sera plus valide, kakaboum…
Ouin, bon, vous me direz, suffit de prendre un domaine qui fait la même taille… C’est exact, c’est ce que j’ai fait, mais avouez, quand même, c’est d’un crétin !
Posté par Mathieu Arnold le mardi 6 novembre 2007 à 16:43
Rétroliens (0)
La discussion continue ailleurs…
Adresse du rétrolien : http://w.mat.cc/trackback/35
Commentaires