Upload de fichiers et WSGI
Je viens de releaser gp.fileupload 0.5 qui fournis un ensemble de middlewares WSGI pour gérer l'upload de fichiers.
Première utilité: afficher une barre de progression
Et ceci de manière quasi transparente. On colle le gp.fileupload.FileUpload dans sa pile d'application et zou; les formulaire pourvu d'un enctype=multipart/form-data sont attraper au vol par du javascript et une barre de progression s'affiche à la soumission du formulaire. Il y a une petite démo (et une belle doc Sphinx) disponible pour les curieux.
Deuxième utilité: limiter le temps des transactions
En général, on ouvre une transaction, on attends 3 heures qu'un fichier de 300Mo arrive, on se choppe 40 conflits au vol, et avec un peu de chance, la transaction aboutit.
gp.fileupload.Storage catch les requêtes POST et attends d'avoir lu tout son contenu.
Le contenu de la requête est parsé pour en extraire les fichiers qui sont écrit sur le système de fichier dans un répertoire défini.
La requête originale est récrite en remplaçant le contenu original de chaque fichier trouvé par son chemin sur le système de fichier.
C'est seulement ensuite que l'application à la main, avec un POST qui ne dépassera pas le kilo octet. Ainsi le fichier est déjà stocké et la durée de la transaction minimale.
Une option encore pas trop testée permet de desservir toutes les requêtes non text/html depuis le middleware. Une fois que j'aurais un peu mieux testé ce machin, l'utilisation de ce middleware pourra devenir totalement transparente pour l'application.
Je n'ai rien inventé. C'est un système similaire à tramline. Peut être moins optimal car tramline utilise mod_python et est donc totalement indépendant du processus de l'application. Mais bon, je penses que c'est à la fois plus simple d'utilisation (car cela ne nécessite pas Apache et mod_python, justement) et plus transparent pour l'application.
Faire du virtualhosting avec zope façon wsgi
J'en avais ras le bol que Zope nécessite des url complètement tordues pour faire du virtual hosting. Ça m'empêchais entre autre d'utiliser Paste#urlmap pour dispatcher certaines url sur d'autres applis que Zope.
Du coup, j'ai tenté un truc tout con: plutôt que d'utiliser les RewriteRule d'Apache, récrire le PATH_INFO en englobant l'application Zope dans une autre. Et ça marche. Fiesta !
Voilà donc à quoi ça ressemble. J'utilise zopeproject. J'ai donc modifier le machin qui créer l'application Zope. A savoir le fichier startup.py comme ceci:
def application_factory(global_conf, conf='zope.conf', vhost='www.gawel.org'):
vhost = '/++vh++http:%s:80/++' % vhost
zopeapp = zope.app.wsgi.getWSGIApplication(zope_conf)
def zopewrapper(environ, start_response):
environ['PATH_INFO'] = vhost + environ['PATH_INFO']
return zopeapp(environ, start_response)
return zopewrapper
Et hop, ça roule. L'avantage, en plus d'avoir une url propre en entrée, c'est que vu que je développe aussi derrière Apache, j'ai juste eu à changer mon fichier debug.ini pour prendre en compte mon virtual host de développement.
En fait j'ai fais un peu mieux que tout ça, car comme dit au début, le but était d'utiliser Paste#urlmap. La source de la bidouille en question est ici.
Aller, pendant que j'y suis, j'en chiais aussi pas mal pour déterminer vers quel backend rediriger les requêtes dans varnish. Tester des ++ dans l'url, ça lui plaisait pas du tout. Vu que j'utilise Apache devant (surtout pour subversion), j'ai trouvé le truc. Il suffit d'activer le module headers:
# a2enmod headers
Puis rajouter un truc du genre dans votre virtualhost Apache:
RequestHeader set VARNISH_BACKEND gawel_org
Vous l'aurez compris, ceci ajoute un header à la requête. Ensuite, dans varnish, on test ce header:
if (req.http.VARNISH_BACKEND ~ "gawel_org") {
set req.backend = gawel_org;
}
Et le tour est joué. Il faut bien sur que toutes les requêtes entrantes aient ce header. Pour moi ce n'est pas un problème vu que tout passe par apache.