Perl-Modul mit der Funktion von mod_gzip
Erik
- perl
Hi,
gibt es ein Perl-Modul das die Funktion des Apache-Modules mod_gzip übernehmen kann, wenn der Hoster dieses nicht installiert hat?
MfG
Erik
Hi Erik,
gibt es ein Perl-Modul das die Funktion des Apache-Modules mod_gzip
übernehmen kann, wenn der Hoster dieses nicht installiert hat?
hm ... das ist nicht so einfach.
Also erstens einmal ist ein großer Teil dessen, was mod_gzip tut, gar
nicht mal das Komprimieren selbst. Dieses könntest Du sicherlich als
Modul irgendwo her bekommen. Schlimmstenfalls könntest Du Deinen Content
über eine pipe in ein "/usr/local/bin/gzip" oder so ähnlich jagen.
Wahrscheinlich gibt es aber in den Tiefen des CPAN schon einen gzipper.
Das löst aber einen großen Teil der Probleme nicht.
Diese gehen schon mal damit los, daß man herausfinden muß, ob der Client
überhaupt komprimierte Daten empfangen will. Dazu muß man in seinem
HTTP-Header nachsehen - das könnte ein Modul durchaus tun.
Als nächstes sollte man sich Gedanken darüber machen, ob man dem Client
glauben will. Es ist nämlich mitnichten so, daß der Client in jedem Fall,
in dem er behauptet, komprimierte Daten zu verstehen, das auch tatsächlich
tut. Neben HTML gibt es noch eine Menge anderer Dinge, die man mit HTTP
über die Leitung jagen kann ... mod_gzip muß sich da mit eine Menge Zeug
herumschlagen, die an dieser Stelle wohl zu weit führen würden. Reduzie-
ren wir Deinen Fall mal auf HTML, das vereinfacht die Sache schon sehr.
Tja, und wenn Du Dir sicher bist, daß Du komprimiert kommunizieren
willst, dann mußt Du es auch noch tun. Das ist nicht damit getan, daß
Du einfach komprimierte Daten auf die Leitung kippst - Du mußt sie in
einer Art und Weise verpacken, daß sie der Client auch wieder lesen kann.
Du mußt also den HTTP-Header mit den entsprechenden Informationen versehen.
Insbesondere muß da ganz vorne drin stehen, wie lang der komprimierte
Inhalt ist - Du mußt also zuerst komprimieren, dann den Header basteln
und die komprimierten Daten derweil irgendwo zwischenspeichern.
Und zu allem Überfluß ist das Basteln des Headers eine Aufgabe, die
normalerweise nur zu einem sehr kleinen Teil das CGI-Skript erledigt.
Du wirst gerade mal den Content-type setzen, den Rest macht der Web-
server für Dich. Und zwar nachdem Du Deine Ausgaben auf die "Leitung"
gekippt und die Kontrolle aufgegeben hast! Der Webserver (puffert die
Daten nämlich auch erst mal und tut genau das, was ich gerade beschrie-
ben habe: Er fügt diejenigen HTTP-Header dazu, von denen sinnvoller-
weise nur er die passenden Werte setzen kann (so Sachen wie seinen
Server-Namen, die aktuelle Uhrzeit etc.). Dein Skript ist leider schon
beendet und kann jetzt nicht nachträglich eingreifen - mod_gzip kann
das, weil es sich in einer Weise in die Apache-Ablaufkette hinein hängt,
welche (meistens) sicherstellt, daß sein mod_gzip_handler noch einmal
aufgerufen wird, bevor die Antwort auf die Reise geht. Und erst in
diesem allerletzten Moment fängt mod_gzip an, wirklich zu arbeiten -
wenn es sicher ist, daß ihm danach niemand mehr ins Handwerk pfuscht,
aber auch vorher schon alle Leute ihren Senf dazu gegeben haben.
Eine Lösung über ein Perl-Modul halte ich also aus rein architektonischen
Gründen für ziemlich schwierig. Wenn überhaupt, dann solltest Du Dir
Gedanken über NPH-Skripte machen (non parsed header - da hättest Du die
Kontrolle, sämtliche HTTP-Header zu basteln, Du mußt dann aber auch alles
selbst und vor allem korrekt tun).
Ich verwende selbst ein Programm (ein Binary, vermutlich in C), dessen
Autor sich tatsächlich die Mühe gemacht hat, "Content-Encoding: gzip"
selbst zu implementieren ... es geht also. (Und das Mistding hat nicht
mal einen Schalter, um die Komprimierung abzuwürgen - das versaut mir
meine ganze schöne statistische mod_gzip-Traffic-Analyse ...)
Anders könnte die Sache aussehen, wenn Dein Provider mod_perl verwendet
Wenn ich es recht bedenke, dann <werbung>dürften Webhosting-Angebote wie
die des Self-Portal-Sponsors PrimeKom für solche Extrawürste eine wirt-
schaftlich vertretbare Plattform bieten können ...</werbung>
Viele Grüße
Michael
Moin
hm ... das ist nicht so einfach.
Hmm, bei PHP scheint das aber durchaus einfach zu sein :) (s.u.)
Diese gehen schon mal damit los, daß man herausfinden muß, ob der Client
überhaupt komprimierte Daten empfangen will. Dazu muß man in seinem
HTTP-Header nachsehen - das könnte ein Modul durchaus tun.
Die Request-Header sollten in einem Skript doch wohl zu bekommen sein?
Als nächstes sollte man sich Gedanken darüber machen, ob man dem Client
glauben will. Es ist nämlich mitnichten so, daß der Client in jedem Fall,
in dem er behauptet, komprimierte Daten zu verstehen, das auch tatsächlich
tut. Neben HTML gibt es noch eine Menge anderer Dinge, die man mit HTTP
über die Leitung jagen kann ... mod_gzip muß sich da mit eine Menge Zeug
herumschlagen, die an dieser Stelle wohl zu weit führen würden. Reduzie-
ren wir Deinen Fall mal auf HTML, das vereinfacht die Sache schon sehr.
Das verstehe ich jetzt nicht ganz?
Wenn da ein Header
Accept-Encoding: gzip
gesendet wird, dann versichert mir der Client das er diese Kodierung versteht und bereit ist sie zu aktzeptieren. Wenn er das nicht ist, dann ist es so, dass er entweder a) lügt oder b) kein HTTP kann.
Bei a) hat er es nicht anders gewollt, und bei b) halte ich einen Programmierfehler der einfach mal so einen zusätzlichen Header in den Request einschleust, für relativ unwahrscheinlich.
Was HTML oder nicht-HTML angeht: Spielt das denn überhaupt eine Rolle? Diese Kodierung ist doch nur für die Übertragung da, und wird nach dem Empfang sofort wieder entfernt. Was auch immer hinter dem HTTP-Teil des Clients liegt, sollte davon nichts mehr mitkriegen. Allenfalls die Nutzlosigkeit des gzippens von JPEG-Daten erscheint mir problematisch, aber das sollte bei Perl-Skripten eher selten vorkommen, und wenn, dann weiss ich als Programmierer dass ich jetzt nur schwer komprimierbare Daten senden werde.
[Header und Inhaltslänge]
Auch da sehe ich ein Problem nicht. Lass den Server tun, was er normalerweise tut. Er kennt doch auch sonst einen Weg die Daten irgendwie zum Client zu schaffen, auch wenn das Skript nicht komprimiert. Der einzige Unterschied ist a) die Daten sind anders (das geht den Server aber nichts an, da er sich die Daten normalerweise auch nicht anschaut) und b) es muß _ein_ zusätzlicher Header gesendet werden:
Content-Encoding: gzip
und auch da mischt sich der Server doch normalerweise nicht ein?
Das mit der Länge muss der Server so halten, wie immer:
a) HTTP/1.1, dann geht in jeden Fall Tranfer-Encoding: chunked
b) HTTP/1.0, dann macht der Server entweder Connection: Close oder er speichert sich bei Keep-Alive alle Daten zwischen und kann dann einen Content-Length Header senden. Das alles geht das Skript aber nichts an, da es ja einfach bloß Daten liefern muß.
[ob_gzhandler]
Der ist ja auch bloß dafür gedacht, es möglichst einfach zu machen.
Richtige Männer ( :-) ) oder solche die kein PHP >= 4.0.4 haben, bauen das zu Fuß. In etwa so:
ob_start(); // Outputbuffering starten
..der rest des skripts...
$content = ob_get_contents(); // Skriptausgaben holen
ob_end_clean(); // Outputbuffering beenden
if(preg_match("/gzip/", $HTTP_SERVER_VARS["HTTP_ACCEPT_ENCODING"])) {
// Herausfinden, ob der Client komprimierte Daten will
header("Content-Encoding: gzip");
echo gzencode($content); // Komprimieren und senden
} else echo $content;
Und du willst mir doch wohl nicht erzählen dass ein fest kompiliertes Modul, dass sich nur über die Serverkonfigurationsdatei konfigurieren lässt, flexibler ist, als etwas dass du selbst in den Scriptcode schreibst?
In Perl müsste das alles ähnlich oder äquivalent gehen, auch wenn ich keinen blassen Schimmer hätte, wie ich etwas ähnliches wie die Outputbufferingfunktionen implementieren sollte. (Ist PHP am Ende gar doch besser als Perl? :)
--
Henryk Plötz
Grüße aus Berlin
Hi Henryk,
hm ... das ist nicht so einfach.
Hmm, bei PHP scheint das aber durchaus einfach zu sein :) (s.u.)
Die beschränken sich halt auf einen stark reduzierten Einsatzfall.
Und wer behauptet, daß das Verfahren in jedem Fall funktioniert?
Schick doch mal ein mit PHP generiertes JavaScript an einen Netscape4 ...
Die Request-Header sollten in einem Skript doch wohl zu bekommen sein?
Klar.
Wenn da ein Header
Accept-Encoding: gzip
gesendet wird, dann versichert mir der Client das er diese Kodierung
versteht und bereit ist sie zu aktzeptieren. Wenn er das nicht ist,
dann ist es so, dass er entweder a) lügt oder b) kein HTTP kann.
Netscape 4.06-4.79 lügt, daß sich die Balken biegen.
Auch einige M$IE verhalten sich in gewissen Fällen "kreativ".
Was HTML oder nicht-HTML angeht: Spielt das denn überhaupt eine Rolle?
Ja, leider.
Diese Kodierung ist doch nur für die Übertragung da, und wird nach dem
Empfang sofort wieder entfernt.
Was auch immer hinter dem HTTP-Teil des Clients liegt, sollte davon
nichts mehr mitkriegen.
Tja, sag das mal den Programmierern der Browser.
Schau einfach mal in den Browser-Cache, wenn Du komprimierte Sachen saugst.
Allenfalls die Nutzlosigkeit des gzippens von JPEG-Daten erscheint mir
problematisch,
Sofern dabei die Daten nicht unbrauchbar werden (auch solche Browser gibt
es), ist das lediglich Zeitverschwendung.
Auch da sehe ich ein Problem nicht. Lass den Server tun, was er
normalerweise tut. Er kennt doch auch sonst einen Weg die Daten
irgendwie zum Client zu schaffen, auch wenn das Skript nicht
komprimiert.
Den darf er aber leider nicht bedenkenlos verwenden.
Der einzige Unterschied ist a) die Daten sind anders (das geht den
Server aber nichts an, da er sich die Daten normalerweise auch nicht
anschaut) und b) es muß _ein_ zusätzlicher Header gesendet werden:
Content-Encoding: gzip
und auch da mischt sich der Server doch normalerweise nicht ein?
Ja. Aber Du müßtest wissen, ob Du den Header senden darfst. Das weißt Du
nur dann sicher, wenn Du selbst der Webserver bist (siehe unten).
Das mit der Länge muss der Server so halten, wie immer:
a) HTTP/1.1, dann geht in jeden Fall Tranfer-Encoding: chunked
Theoretisch erlaubt HTTP natürlich die gleichzeitige Verwendung von Trans-
fer- und Content-Encoding, ja. Theoretisch erlaubt es auch die Verwendung
von beliebig vielen Content-Encodings (man darf sie also schachteln).
Aber kennst Du einen Browser, der das überlebt?
mod_gzip buffert die gesamten Chunks und faßt sie zu einem Paket zusammen.
(Natürlich nur, wenn man das in der Konfiguration so eingestellt hat; an-
dernfalls läßt es die Finger von allem, was irgend ein Encoding besitzt.)
Das alles geht das Skript aber nichts an, da es ja einfach bloß Daten
liefern muß.
Wäre es nicht schön, wenn der Browser diese Daten auch lesen könnte?
(Und dabei nicht abstürzt?)
if(preg_match("/gzip/", $HTTP_SERVER_VARS["HTTP_ACCEPT_ENCODING"])) {
// Herausfinden, ob der Client komprimierte Daten will
header("Content-Encoding: gzip");
echo gzencode($content); // Komprimieren und senden
} else echo $content;
Tja, damit wirst Du den einen oder anderen Browser nicht glücklich machen.
Aber falls das nicht wichtig ist, würde es so funktionieren.
Und du willst mir doch wohl nicht erzählen dass ein fest kompiliertes
Modul, dass sich nur über die Serverkonfigurationsdatei konfigurieren
lässt, flexibler ist, als etwas dass du selbst in den Scriptcode
schreibst?
mod_gzip versendet ja nicht nur die Daten Deines einen Skripts, von dem
Du zufällig gerade weißt, was es versendet.
mod_gzip versucht, für Dutzende verschiedener Arten von Daten, Übertra-
gungsmodalitäten, Erzeugungsmethoden usw. das 'Richtige' zu tun, eben
damit niemand alles umschreiben muß.
In Perl müsste das alles ähnlich oder äquivalent gehen, auch wenn ich
keinen blassen Schimmer hätte, wie ich etwas ähnliches wie die Output-
bufferingfunktionen implementieren sollte.
In diesem Bereich wüßte ich aus dem Kopf auch nichts Passendes.
Die Probleme sehe ich aber woanders - und einige davon kann auch mod_gzip
nicht lösen.
Was hältst Du denn z. B. von Caching von gzipped content in Proxies?
Ich habe bei Deinem Skript oben keinen "Vary:"-Header gesehen ...
Sicherlich kannst Du ein Perl-Skript einfach komprimierte Daten versenden
lassen. Und vielleicht verstehen das auch die meisten der modernen Browser.
Viele Grüße
Michael
Hi Henryk,
Auch da sehe ich ein Problem nicht. Lass den Server tun, was er normalerweise tut. Er kennt doch auch sonst einen Weg die Daten irgendwie zum Client zu schaffen, auch wenn das Skript nicht komprimiert. Der einzige Unterschied ist a) die Daten sind anders (das geht den Server aber nichts an, da er sich die Daten normalerweise auch nicht anschaut) und b) es muß _ein_ zusätzlicher Header gesendet werden:
Content-Encoding: gzip
und auch da mischt sich der Server doch normalerweise nicht ein?
muss dieser zusätzliche Header vor oder nach Content-type: text/html gesendet werden oder muss da sonst noch irgendwas beachtet werden? (ich hab´s in allerlei Kombinationen ausprobiert hat aber nie geklappt.)
MfG
Erik
Moin
muss dieser zusätzliche Header vor oder nach Content-type: text/html gesendet werden oder muss da sonst noch irgendwas beachtet werden? (ich hab´s in allerlei Kombinationen ausprobiert hat aber nie geklappt.)
Also in HTTP sollte die Reihenfolge der Header meist ziemlich egal sein (es gibt evt. Ausnahmen) aber der Apache beschwert sich bei CGI-Skripten, wenn der Content-Type:-Header nicht als erstes kommt.
print "Content-Type: text/html\n";
print "Content-Encoding: gzip\n\n";
tut bei mir in einem provisorisch zusammengestöpselten Testscript ganz hervorragend.
--
Henryk Plötz
Grüße aus Berlin
Hi Michael,
danke erstmal für deine ausführliche Antwort (auch an Henryk).
Also erstens einmal ist ein großer Teil dessen, was mod_gzip tut, gar
nicht mal das Komprimieren selbst. Dieses könntest Du sicherlich als
Modul irgendwo her bekommen. Schlimmstenfalls könntest Du Deinen Content
über eine pipe in ein "/usr/local/bin/gzip" oder so ähnlich jagen.
Wahrscheinlich gibt es aber in den Tiefen des CPAN schon einen gzipper.
Das löst aber einen großen Teil der Probleme nicht.
Genau so ein Modul ist wohl das von Karl (Compress:Zlib) genannte, oder?
Wenn ich es recht bedenke, dann <werbung>dürften Webhosting-Angebote wie
die des Self-Portal-Sponsors PrimeKom für solche Extrawürste eine wirt-
schaftlich vertretbare Plattform bieten können ...</werbung>
Hm, vielleicht. Arbeitest du bei denen? ;-)
Viele Grüße
Erik
gibt es ein Perl-Modul das die Funktion des Apache-Modules mod_gzip übernehmen kann, wenn der Hoster dieses nicht installiert hat?
use Compress::Zlib;
hat auch ein gzip-Interface:
"GZIP INTERFACE
A number of functions are supplied in zlib for reading and writing gzip files. ...."
--> im CPAN danach suchen; unter U*x brauchst Du aber einen (g)cc um das zu installieren - oder falls Dein Server under einer Linux Distribution läuft, solltest Du mal nach einer passenden Binärdistribution suchen.
Ich verarbeite übrigens auf meinem angemieteten Server Space PKZIP Dateien (das unter winDOS übliche .zip) - und spreche infozip über IPC:Open3 an. Geht easy, sicher + schnell.
Grüße K@rl
----
remove "NOSPAM" from my mail address
PS:
wegen "unter U*x brauchst Du aber einen (g)cc um das zu installieren"
probier lieber erst mal
"use Compress::Zlib;"
bevor du das Suchen nach einer Binärdistriburion anfängst - Zlib sollte standardmäßig installiert sein.
Hi Karl,
bist du sicher, dass dieses Modul das bietet was mod_gzip bietet (sofern möglich komprimierte Ausgabe der HTML-Daten an den Browser)? Dazu müsste, wie Michael schreibt, ja auch der Header und alles geändert werden. Außerdem müsste ich, wenn ich das richtig verstehe, alles was ich ausgeben will, sammeln um es dann auf einmal komprimieren zu können, das würde einen doch ziemlich einschränken.
Viele Grüße
Erik
Hallo Erik,
bist du sicher, dass dieses Modul das bietet was mod_gzip bietet (sofern möglich komprimierte Ausgabe der HTML-Daten an den Browser)? Dazu müsste, wie Michael schreibt, ja auch der Header und alles geändert werden. Außerdem müsste ich, wenn ich das richtig verstehe, alles was ich ausgeben will, sammeln um es dann auf einmal komprimieren zu können, das würde einen doch ziemlich einschränken.
Ich leiste hiermit öffentlich Abbitte - ich habe mir den Thread nicht bis ins Letzte durchgelesen.
Sorry + noch viel Erfolg bei der Sache -- vielleicht hilft eine CPAN-Suche weiter?
Grüße
K@rl
Hi Karl,
Ich leiste hiermit öffentlich Abbitte - ich habe mir den Thread nicht bis ins Letzte durchgelesen.
Kein Problem.
Sorry + noch viel Erfolg bei der Sache -- vielleicht hilft eine CPAN-Suche weiter?
Wie´s aussieht wohl nicht.
Viele Grüße
Erik
Hi Erik,
bist du sicher, dass dieses Modul das bietet was mod_gzip bietet (sofern möglich komprimierte Ausgabe der HTML-Daten an den Browser)?
Das zwar nicht (um den HTTP-Header etc. müßtest Du Dich selbst kömmern - aber vielleicht ist Dein Einsatzfall ja speziell genug, daß Du es hin bekommst), aber für den Teil, die Daten zu komprimieren, könnte das genau das Richtige sein.
(Über die zlib selbst habe ich übrigens nicht nur Gutes gehört, was deren Performance angeht; mod_gzip hat deshalb - sagt sein Autor - die Komprimierung selbst neu implementiert.)
Außerdem müsste ich, wenn ich das richtig verstehe, alles was ich ausgeben will, sammeln um es dann auf einmal komprimieren zu können, das würde einen doch ziemlich einschränken.
Das kommt eben auf Deinen Einsatzfall an.
Wenn Du wirklich nur ein Standalone-CGI-Skript bauen willst, schränkt Dich das nur insofern ein, als Du statt nach stdout zu schreiben eine eigene Aufsammel-Funktion bauen und ein bißchen RAM für den Puffer spendieren mußt.
Solange es nicht mehr ist, probiere es einfach aus - schreibe mal ein kleines Skript, bei dem Du die Länge der Ausgabe und den Encoding-Typ (es gibt da auch einen neutralen Wert, der 'uncodiert' bedeutet) setzt, und schau nach, ob der Apache alles so durchläßt, wie Du es willst. Wenn das alles klappt, kannst Du Dich um die Komprimierung selbst kümmern.
Wenn Du Deine Ausgabe aber mit anderen Dingen kombinieren willst, könnte es Probleme geben. Beispielsweise wäre es wohl schon ein Unterschied, ob das Skript standalone oder via SSI gestartet wird - SSI verwendet chunking ... und ob die Browser damit dann noch klar kommen, weiß der Himmel.
Viele Grüße
Michael
Moin
Wenn Du Deine Ausgabe aber mit anderen Dingen kombinieren willst, könnte es Probleme geben. Beispielsweise wäre es wohl schon ein Unterschied, ob das Skript standalone oder via SSI gestartet wird - SSI verwendet chunking ... und ob die Browser damit dann noch klar kommen, weiß der Himmel.
Ich sehe bei Chunked keine Probleme. Folgendes kleines Test-Skript habe ich verwendet:
#!/usr/bin/perl
print "Content-Type: text/html\n";
print "Content-Encoding: gzip\n\n";
open(HH,"</tmp/192.html.gz");
while(<HH>) {
print $_;
}
Wobei die Datei die da ausgegeben wird, eine ganz normal auf der Kommandozeile mit gzip komprimierte Datei ist.
Nachfolgend die zwischen Server und Browser ausgetauschten Header:
In Galeon 1.0.3 (verwendet Mozilla 0.9.8):
GET /cgi-bin/192_test.pl HTTP/1.1
Host: fuzzy.homeip.net
User-Agent: Mozilla/5.0 Galeon/1.0.3 (X11; Linux i686; U;) Gecko/20020206
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1
Accept-Language: de, en;q=0.50
Accept-Encoding: gzip, deflate, compress;q=0.9
Accept-Charset: ISO-8859-1, utf-8;q=0.66, *;q=0.66
Keep-Alive: 300
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
HTTP/1.1 200 OK
Date: Sun, 24 Feb 2002 18:43:59 GMT
Server: Apache/1.3.19 (Unix) (SuSE/Linux) mod_throttle/3.0 PHP/4.0.4pl1 mod_layout/1.0 mod_dtcl mod_fastcgi/2.2.2 mod_perl/1.25 mod_python/2.7.2 Python/2.0 mod_ssl/2.8.3 OpenSSL/0.9.6a
Content-Encoding: gzip
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html
Danach kommen dann die gezippten Daten mit Chunked-Encoding. Da die Daten scheinbar alle in einen Buffer passen, kommt nur ein Chunk und danach der Abschluss-Chunk mit der Länge 0. Fällt dir vielleicht ein Weg ein, wie man bei diesem Fall das doch recht sinnfreie Chunking abschalten kann?
In Netscape 4:
GET /cgi-bin/192_test.pl HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/4.77 [de] (X11; U; Linux 2.4.4-4GB i686)
Pragma: no-cache
Host: fuzzy.homeip.net
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
Accept-Encoding: gzip
Accept-Language: de, en
Accept-Charset: iso-8859-1,*,utf-8
HTTP/1.1 200 OK
Date: Sun, 24 Feb 2002 18:49:39 GMT
Server: Apache/1.3.19 (Unix) (SuSE/Linux) mod_throttle/3.0 PHP/4.0.4pl1 mod_layout/1.0 mod_dtcl mod_fastcgi/2.2.2 mod_perl/1.25 mod_python/2.7.2 Python/2.0 mod_ssl/2.8.3 OpenSSL/0.9.6a
Content-Encoding: gzip
Connection: close
Content-Type: text/html
Danach kommen die gezippten Daten, ungechunkt (weil Chunked bei HTTP 1.0-Clients nicht zwangsweise unterstützt werden muss). Das ganze funktioniert auch mit Lynx und das Verhalten ist dann identisch zu dem von NN4 (naja, bis auf die Tatsache, dass Lynx zwei Tonnen voll Accept:-Header sendet).
Mehr Browser hab ich grade hier nicht zur Verfügung.
Erik: Denk dran dass du wenn du Content-Encoding: gzip verwendest dich auch an die gzip-Struktur hältst. Das schliesst den 10Byte-Vorspann mit ein!
PS: Habe das grade nochmal mit Daten probiert die nicht alle in einen Chunk passen. -> Kein Problem
PPS: Mir fällt grade auf dass das genau bei jedem zweiten Ladeversuch schiefgeht und zu einem 500 mit "Premature end of script headers" führt. Kann das jemand erklären?
--
Henryk Plötz
Grüße aus Berlin
Hi Henryk,
interessante Experimente, die Du da machst - danke schön!
Eigentlich brauchst Du jetzt nur noch den HTTP-Header abzufragen:
if ($ENV {'HTTP_ACCEPT_ENCODING'} =~ /\bgzip\b/)
und dann müßte man noch irgendwie alle Ausgaben in einen Puffer umlenken.
(Kann man in Perl irgendwie STDOUT an einen eigenen Treiber binden?)
Ich sehe bei Chunked keine Probleme.
Ich schon - weil Du eben nicht nur einen einzigen nagelneuen Browser
testen darfst, sondern _alle_ testen müßtest.
Dein Mozilla 0.9.8 kann ja auch schon "AuthType: Digest" ...
Content-Encoding: gzip
Transfer-Encoding: chunked
Fein. Dasselbe jetzt bitte noch mit Netscape 4.5 und M$IE 5.0 (mindestens)
testen, dann wird die Aussage wahrscheinlich schon ziemlich interessant.
Da die Daten scheinbar alle in einen Buffer passen, kommt nur ein
Chunk und danach der Abschluss-Chunk mit der Länge 0.
Fällt dir vielleicht ein Weg ein, wie man bei diesem Fall das doch
recht sinnfreie Chunking abschalten kann?
Leider nein.
Ich vermute, der Apache weiß, daß er eine dynamisch lange Ausgabe produ-
ziert (er führt ja gerade ein CGI-Skript aus) und hofft, daß hinter ihm
niemand mehr etwas puffern muß (an ein eventuelles mod_gzip denkt er
nicht präventiv).
Falls dies alles zutrifft und er Chunking verwendet, kann den HTTP-Header
schon vor der Ausführung des Skripts erzeugen - daß er dann auch den Son-
derfall mit nur einem Chunk produziert, muß "im Etat drin" sein. Er kann
ja schlecht in die Zukunft sehen und prüfen, ob er das Chunking brauchen
wird oder nicht ...
HTTP/1.1 200 OK
Danach kommen die gezippten Daten, ungechunkt (weil Chunked bei HTTP
1.0-Clients nicht zwangsweise unterstützt werden muss).
Hoppla - wie passen die beiden obigen Aussagen zusammen?
(Mich wundert auch, daß der Apache eine HTTP/1.0-Anfrage in HTTP/1.1 zu
beantworten versucht - ich dachte, der Server darf nur 'dümmer' antworten,
nicht aber 'schlauer'?)
Viele Grüße
Michael
Moin
Eigentlich brauchst Du jetzt nur noch den HTTP-Header abzufragen:
if ($ENV {'HTTP_ACCEPT_ENCODING'} =~ /\bgzip\b/)
[X] done
und dann müßte man noch irgendwie alle Ausgaben in einen Puffer umlenken.
(Kann man in Perl irgendwie STDOUT an einen eigenen Treiber binden?)
Isch kann doch gar kein perl :) Ich bastle aber grade an einem Beispielscript dass das mehr oder weniger hinkriegt. Code kommt sobald er funktioniert.
Kann vielleicht ein Perlophile noch was dazu sagen?
Fein. Dasselbe jetzt bitte noch mit Netscape 4.5 und M$IE 5.0 (mindestens)
testen, dann wird die Aussage wahrscheinlich schon ziemlich interessant.
Ich habe solche Altgüter zwar nicht mehr auf der Platte (nicht mal ein Windows) probier das aber mal zu Hause bei meinem Vater aus.
Leider nein.
Ich vermute, der Apache weiß, daß er eine dynamisch lange Ausgabe produ-
ziert (er führt ja gerade ein CGI-Skript aus) und hofft, daß hinter ihm
niemand mehr etwas puffern muß (an ein eventuelles mod_gzip denkt er
nicht präventiv).
Wie ich grade herausgefunden habe ist der Indianer hier schlauer als man denken mag. Wenn das Skript einen Content-Length:-Header sendet, gibt er diesen an den Client weiter und spart sich das chunken. Die 1.1-Antwort an 1.0-Clients bleibt davon aber unberührt.
Hoppla - wie passen die beiden obigen Aussagen zusammen?
(Mich wundert auch, daß der Apache eine HTTP/1.0-Anfrage in HTTP/1.1 zu
beantworten versucht - ich dachte, der Server darf nur 'dümmer' antworten,
nicht aber 'schlauer'?)
Hmm, das hat mich auch gewundert. Im RFC 2616 hab ich dazu nur gefunden 'Applications that are at least conditionally compliant with this specification SHOULD use an HTTP-Version of "HTTP/1.1" in their messages, and MUST do so for any message that is not compatible with HTTP/1.0.', dass er also HTTP/1.1 verwenden muss, wenn die kommende Nachricht nicht mit 1.0 kompatibel ist. Da das hier aber nicht der Fall ist, sehe ich den Grund dafür auch nicht. Bug?
--
Henryk Plötz
Grüße aus Berlin
Tach Henryk,
Erik: Denk dran dass du wenn du Content-Encoding: gzip verwendest dich auch an die gzip-Struktur hältst. Das schliesst den 10Byte-Vorspann mit ein!
Blöde Frage, aber: welchen 10-Byte-Vorspann?
Viele Grüße
Erik
Moin
Blöde Frage, aber: welchen 10-Byte-Vorspann?
Wenn man Daten mit gzip komprimiert, packt es einen Header davor der einige Meta-Informationen, unter anderem zum Beispiel das Modifikationsdatum der Originaldatei oder das verwendete OS enthält. Von den in PHP vorhandenen Funktionen zum Komprimieren, tut nur gzencode() auch so einen Vorspann davortun. Wie ich von Christian weiss, tut Compress::Zlib::compress in Perl so einen Vorspann nicht davor sondern gibt nur die reinen komprimierten Daten.
Daten die mit Content-Encoding: gzip gesendet werden, müssen aber diesen Vorspann enthalten, sonst wirst du keine Freude daran haben.
Rein empirisch hatte ich angenommen dass der Header immer 10 Bytes lang ist, da sowohl gzencode() von PHP als auch das was mod_gzip produziert 10 Bytes vor den eigentlichen Daten hat (in PHP merkt man das daran, dass man die ersten 10 Bytes von mod_gzip-Ausgaben abschneiden muss, bevor man es durch gzinflate() jagt).
Aber da lesen ja bekanntlich nicht dümmer macht, hab ich grade mal in RFC 1952 reingeschaut und festgestellt, dass diese 10 Bytes nur das absolute Minimum an Header sind. Mehr wirst du aber trotzdem nicht brauchen, nur vorhanden muss er eben sein.
--
Henryk Plötz
Grüße aus Berlin