Der Martin: Demo: JavaScript und Binärdateien, Multimedia

Beitrag lesen

Moin Christian,

AFAIK nimmt der Webserver den vollständigen POST-Request entgegen, bevor er den PHP-Prozess überhaupt startet.

Das ist hochgradig Server-spezifisch. Apache ist nicht der einzige Server.

aber vermutlich der meistverbreitete. Egal, mir ist hinterher auch klar geworden, dass ich mich hier vermutlich geirrt habe.

Per Default liest der Apache nicht zuerst den POST-Request, bevor er das CGI-Script startet, sondern er streamt den Request in chunks. Das Herz-Stück ist dabei diese Code-Stelle:

            /* read */
            apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);

            if (conf->logname && dbpos < conf->bufbytes) {
                int cursize;

                if ((dbpos + len) > conf->bufbytes) {
                    cursize = conf->bufbytes - dbpos;
                }
                else {
                    cursize = len;
                }
                memcpy(dbuf + dbpos, data, cursize);
                dbpos += cursize;
            }

            /* Keep writing data to the child until done or too much time
             * elapses with no progress or an error occurs.
             */
            rv = apr_file_write_full(script_out, data, len, NULL);

Dieser Code wird in einer Loop aufgerufen, Apache liest also den Body in Blöcken der Maximal-Größe APR_BLOCK_READ aus dem Bucket und schreibt ihn ins STDIN des CGI.

Ja, an diesen Mechanismus (also dass das CGI die Daten durch stdin erhält) habe ich mich dann auch erinnert, und da spricht natürlich nichts dagegen, den CGI-Prozess quasi sofort zu starten und ihm dann die Daten zu streamen. Im Gegenteil, das wäre sogar deutlich effizienter als hier schon zu puffern.

Ein Bucket ist dabei eine Abstraktion einer I/O-Schnittstelle, und hier kommt dann auch das Problem zum tragen: Apache hat sog. Filters, das ist ein Stück Software, dass sowohr VOR dem Request als auch nach dem Request über die Daten laufen kann, und die, klar, nacheinander ab. Es ist also prinzipiell möglich, dass ein Filter den Request vor der Verarbeitung liest.

Das ist aber, wie gesagt, in der Default-Konfiguration nicht der Fall!

Dann ist es wohl der PHP-Prozess, der die Daten zwischenspeichert, bevor er das eigentliche Script startet. Denn das muss er, wie ich schon an anderer Stelle argumentiert habe, damit er bei File-Uploads die maximale Dateigröße prüfen kann. Nicht die Gesamtgröße des POST-Requests, die könnte man ja auch aus dem Content-Length-Header holen, sondern die "Nettogröße" der hochgeladenen Datei(en).

Und das ist der eigentliche Punkt, auf den ich hinaus wollte: Wenn das PHP-Script startet, ist der Request schon vollständig zum Server übermittelt worden.

So long,
 Martin

--
Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
- Douglas Adams, The Hitchhiker's Guide To The Galaxy