Christian Kruse: multipart/form-data

Beitrag lesen

Hallo pl,

eigentlich wollte ich dir nicht mehr antworten, aber… meh.

Nochmal: Dateien sind Sequenzen, sie werden sequentiell erzeugt und sequentiell gelesen.

Das ist nicht richtig. Sie können sequentiell gelesen oder geschrieben werden. Random-Zugriff ist allerdings auch möglich, siehe lseek(2)/fseek(3) und Konsorten. Genau genommen liegt übrigens eine Datei oft gar nicht wirklich sequentiell vor, die Inhalte von Dateien können sich an beinahe beliegen Orten der Festplatte befinden (Stichwort Fragmentierung). Das Konstrukt Datei ist ein rein logisches und hat nichts mit sequentiellem/zufälligem Zugriff zu tun.

Ein Token ist letztendlich auch nur eine Sequenz.

Ein Token ist die kleinste sinngebende Einheit in einer Grammatik bzw formalen Sprache. Was du hier mit Sequenz (lt Wikipedia Reihenfolge, Ordung) meinst ist nicht klar.

Daraufhin glaubtest du, dass das mit Binärdaten nicht funktionieren könne.

Es kann schiefgehen. Besser als ein Tokenizer ist ein sequentielles Parsen auf Byte-Ebene.

Das, was du als „sequentielles Parsen auf Byte-Ebene“ bezeichnest, ist Teil der lexikalischen Analyse eines Tokenizers. Der macht (stark vereinfacht) nichts anderes als deinen Eingabestrom durchzugehen und dort Zeichen für Zeichen solange das Wort (Token) zusammenzubauen, bis er ein vollständiges Wort (Token) erhalten hat. Das gibt er dann weiter.

Das, was 1UnitedPower dir vorgeschlagen hat, ist die Unterteilung der logischen Einheiten deines Parsers in lexikalische Analyse (Tokenizer) und semantische Analyse (Parser). Das daraus resultierende Konstrukt ist besser wartbar, einfacher erweiterbar und nicht so ein monolithyscher Block wie eine Vermischung der beiden Phasen.

Dieses Prinzip beschreibt Wirth übrigens in seinen Lehrbüchern über formale Sprachen und Compilerbau.

Vorausgesetzt, die Datei wurde zweckmäßig erstellt, was bei multipart/form-data nicht unbedingt zutrifft aufrund fehlender Längenangaben (siehe Eröffnungspost).

Da du eh auf einem Eingabestrom arbeitest, sind deine Längenangaben gar nicht notwendig. Im wesentlichen muss dein Parser eine Finite State Machine nachbauen, die bei autreten bestimmter Tokens den Status wechselt. Das Boundary, an dem du dich so gestossen hast, muss so gewählt werden, dass keine Kollision mit dem Inhalt stattfinden kann.

Trotz möglicher Kollisionen halte ich es nach Niklas Wirth und parse einen multipart/form-data sequentiell, das hat sich auch in CGI.pm bewährt was noch viel älter ist als meine eigenen Entwicklungen.

Wenn Du einen multipart/form-data unbedingt mit einem Tokenizer parsen möchtest, bitteschön, mach es einfach.

Ich glaube, dir fehlt es an Verständnis, was ein Tokenizer ist und was er tut. Ob das Parsing sequentiell ist oder nicht, das hat überhaupt nichts mit dem Einsatz eines Tokenizers zu tun. Ein kleines Beispiel: wir betrachten eine einfache formale Sprache L mit den Symbolen +, -, * und / sowie den Ziffern 0 bis 9. Gegeben ist der Eingabestring 1 + 2 * 3 - 4. Der Tokenizer würde jetzt diesen Eingabestring in die einzelnen Symbole 1, +, 2, *, 3, - und 4 zerlegen. Der darauf folgende Parser könnte, ohne sich um die lexikalische Analyse kümmern zu müssen, daraus z.B. einen AST bauen:

   -
4      +
    1    *
       2   3

Das Konzept der Unterteilung in lexikalische Analyse (Tokenizer) und semantische Analyse (Parser) hat also überhaupt nichts mit sequentiell oder nicht-sequentiell zu tun.

Ich kann dir zu diesem Thema das Dragon Book (Compilers: Principles, Techniques and Tools) empfehlen, das Standard-Werk zu diesem Thema. Alternativ auch Compiler Construction von Wirth, wobei ich mit seinem Schreibstil immer Mühe hatte.

LG,
CK

Edit: peinlichen Fehler im AST gefixed ;-)