Léa-Linux & amis :   LinuxFR   GCU-Squad   GNU
gzip encoding en HTTP (fastcgi) avec zlib

Bonjour,

Une question un peu technique pour ceux qui savent coder en C du HTTP 1.1

Contexte: à mes rares heures perdues, je bricole un petit serveur FastCGI pour expérimenter sur mes idées exposées ici
Plus tard, (si j'arrive à quelque chose) l'essentiel du code de ce serveur sera réflexif et auto-généré -et bien évidemment en libre sous license GPLv3 (ou LGPL?), mais pour l'instant, j'en suis juste à faire le "runtime" initial en C.

Mon souci est de produire un contenu compressé. De sorte que si la requête HTTP courante contient dans son entête
Accept-Encoding: gzip
(ce qui est le cas des navigateurs courants) je veux, dans certains cas, effectivement compresser selon l'algorithme gzip.

Ma question précise est: comment produire (en C) un contenu gzippé à partir du contenu initial en mémoire (donc un char*buf de longueur long buflen)

Je pensais que il faut bien évidemment utiliser <zlib.h> (et la traditionnelle zlib) et notamment sa fonction compress. Est ce que cette fonction nommée compress implémente bien la compression gzip du RFC 1952?

Plus précisément, je crois faire la chose suivante. Pour simplifier mon FASTCGI a déjà généré l'entête dans un char* headbuf de longueur int headlen supposée suffisamment longue, donc a exécuté quelque chose du genre de
strcpy(headbuf, 
    "HTTP/1.1 200 OK\r\n"
    "Content-Type: text/html\r\n");
En réalité, le code est plus complexe car il gère convenablement la longueur, alloue les chaînes par des GC_MALLOC_ATOMIC (car j'utilise le GC de Boehm), etc..

Ensuite il génère le corps dans un char* bodybuf de longueur suffisante int bodylen, donc un document HTML avec pour simplifier quelque chose du genre de
sprintf(bodybuf,    "<html><head><title>mon titre</title></head>\n"
"<body>salut %d fois</body></html>\n", compteur);

Dans le cas simple (sans compression gzip), j'envoie l'entête et le corps simplement par
/* ajout de la longueur du corps au bout de l'entête */
sprintf(headbuf+strlen(headbuf),"Content-Length: %d\r\n", strlen(bodybuf));
/* envoi de l'entête avec la ligne vide finale */
FCGX_FPrintF(out, "%s\r\n", headbuf);
/* envoi du corps */
FCGX_PutStr (bodybuf, strlen(bodybuf), out);
et ca marche bien.

Dans certains cas, je désire compresser (si la requête contient Accept-Encoding: gzip et si bodybuf a plus de 1000 octets). J'alloue donc un tampon pour le résultat de la compression
long zlen = 9*headlen/8+40;
char* zbuf = malloc(zlen);
memset(zbuf, 0, zlen);
long bodylen=strlen(bodybuf);
je le comprime par
compress((Bytef *) zbuf, &zlen, (Bytef *)bodybuf, bodylen);
je complète l'entête convenablement par
sprintf(headbuf+strlen(headbuf),
   "Content-Length: %d\r\n"
   "Content-Encoding: gzip\r\n",
   zlen);
Enfin j'envoie l'entête et le corps par
FCGX_FPrintF(out, "%s\r\n", headbuf);
FCGX_PutStr (zbuf, zlen, out);

Et ca ne marche pas (le navigateur n'affiche rien). J'imagine que j'ai mal compressé par gzip le contenu, càd qu'en plus du résultat de compress il faut envoyer un entête (mais je ne me suis pas encore plongé dans RFC 1952

Si vous avez un avis pertinent, faites moi signe.

Désolé d'avoir embêté tous les autres (mais je réponds bien plus souvent sur Léa que je ne pose une question... )

Pour des raisons non exposées ici (ça serait plus simple en MetaOcaml qui hélàs est mort), je tiens à coder en C de bas niveau.

----

Basile STARYNKEVITCH

Membre de l'APRIL « promouvoir et défendre le logiciel libre » - adhérez vous aussi à l'APRIL!

Projet logiciel libre: RefPerSys

Poste le Saturday 10 November 2007 22:01:50
Répondre     Citer    
Re: gzip encoding en HTTP (fastcgi) avec zlib

En fait il semble qu'il faut utiliser (cf zlib faq) la fonction deflateInit2 avec un zstream convenable comme ici ou

Mais je mets ça de coté.


Désolé du dérangement.

----

Basile STARYNKEVITCH

Membre de l'APRIL « promouvoir et défendre le logiciel libre » - adhérez vous aussi à l'APRIL!

Projet logiciel libre: RefPerSys

Poste le Saturday 10 November 2007 22:55:18
Répondre     Citer    

Veuillez vous authentifier auparavant pour commenter.

 

Ce forum !
gzip encoding en HTTP (fastcgi) avec zlib
Pour poser vos questions sur les scripts shell, le Perl, le C, etc... Attention : nous ne sommes pas des spécialistes du dev, ce forum est juste pour de petites aides ponctuelles concernant le développement et les outils de développement.

Sauf mention contraire, les documentations publiées sont sous licence Creative-Commons