File Upload über CGI- exe C++



  • Hallo,

    Ich versuche ein Formular zum Hochladen von Dateien zu erstellen. Das Formular habe ich soweit auch schon fertig. Kann mir bitte jemand sagen, wie ich die Daten in meiner C++ Anwendung entgegennehme und in eine Datei auf dem Server schreibe?

    Ausgangssituation:

    CGI- Anwendung (.exe) mit C++ im MS VS6.0 -Umfeld entwickelt und auf einem Microsoft IIS am laufen.

    gruß

    Robert L.





  • Moin Robert,
    deine cgi Klasse muss in der Lage sein, wenn die Post-Methode verwendet wird, je nach CONTENT_TYPE untersciedlich zu reagieren. 'Content-Type: multipart/form-data;' ist der springende Punkt. Dann muss der Boundary-String rausgefiltert werden.

    HTTP-Header Beispiel
    :: (POST Methode, Abschicken einer UPLOAD - Anforderung)

    POST /uploadexe HTTP/1.1
    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, /
    Referer: http://192.168.1.1/upload.htm
    Accept-Language: de
    Content-Type: multipart/form-data; boundary=7d5370720692
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)
    Host: 192.168.1.1
    Content-Length: 390942
    Connection: Keep-Alive
    Cache-Control: no-cache

    Durch "Content-Type: multipart/form-data;" wird dem Server mitgeteilt, dass jetzt ein mehrteiliges Datenfeld zu erwarten ist. Anfang und Ende Kennzeichnung eines Dateiinhalts erfolgt durch den BOUNDERYSTRING "7d5370720692". Das sollte eine Zeichenkette sein, die in diese Form garantiert micht in den Parts vorkommt und wird vom Browser generiert und in den Header eingefügt. Form des Boundary am Anfang und ggf Zwischen verschiedenen Inhaltn : " --BOUNDERYSTRING ", Form des Boundary am Ende : " --BOUNDERYSTRING--".

    Wie bei allen POST-Headern hier wieder die Length. Sie umfasst die
    Dateigröße in Bytes
    + Header(inkl. BOUNDERYSTRING)des 1. Packets
    + BOUNDERYSTRING-Trailer des letzten Pakets.

    Diese HTML - Anforderung wird vom Server nicht speziell beantwortet, es existiert nur das normale Acknowledgement in der Schicht 3 (TCP).
    Der Client arbeitet von dieser Anforderung bis zum letzten Part immer mit der gleichen Verbindung! Also fleissig an der Socket lesen ;-). Das folgende 1.Part-Paket wird sofort nach dieser Anforderung gesendet,ohne eine Antwort des Servers zu erwarten.

    :: POST Methode, CONTINUATION der UPLOAD - Anforderung (1. Paket mit Upload Daten)

    --7d5370720692
    Content-Disposition: form-data; name="userfile"; filename="C:\HTML\test.txt"
    Content-Type: application/octet-stream

    4Vx Ó' .......usw

    Zum 'Header des ersten 'File-Daten-Pakets' (1.Part) :
    Zunächst kommt der BOUNDERYSTRING in der Form " --$BOUNDERYSTRING"
    Content-Type: application/octet-stream ---> == MIME-Type
    name="userfile"; ---> == Der Name der Inputbox zur Fileauswahl in der HTML-Seite
    filename="C:\HTML\test.txt" ---> Value der Upload-Inputbox
    (Vorsicht, je nach Browser mit/ohne Pfad, mit Slash/Backslash codiert !)
    Wichtigfür den Server ist hier eigentlich zunächst der reine Filename.

    Darauf folgen 2 Leerzeilen (0d0a0d0a), gefolgt von Daten aus dem File.
    Es folgen die weiteren Parts einfach mit der Payload voll von Daten aus dem Upload-File gesendet. Nothing special to do. Sie sind hier nicht wiedergegeben. Die musst du halt von der Socket lesen und dranhängen.

    Das letzte Paket ist interessanter : Wenn die Daten gesendet worden sind, kommt
    1. ein HTML-typischer Zeilenwechsel ( 0d 0a ).
    2. Darauf folgt der BOUNDERYSTRING in der Form " --$BOUNDERYSTRING-- ".
    3. Abschließend erfolgt noch ein HTML-typischer Zeilenwechsel ( 0d 0a ).

    Jetzt ist das File Komplett und der Server kann es zum Beispiel auf die Platte pinseln.Wenn alles gut gelaufen ist, schickst du dein HTTP OK zurück und deine Antwortseite (if any). Die Zeilenwechsel gehören nicht zu den Filedaten!

    Pronto

    Tip. habe bei der Post Methode immer stdin auf Binäres Lesen gesetzt (_setmode(_fileno(stdin), _O_BINARY)), und nach dem Vorgang wieder zurück (_setmode(_fileno(stdin), _O_TEXT)). Erspart dir möglicherweise bei Steuerzeichen auf den unterschiedlichen Betriebssystemen ein paar seltsame Effekte. Ggf einfach mal ausprobieren.

    In der RFC ist sehr schön die Sendung mehrerer Parts in einem POST beschrieben. Du brauchst also eine CGI-Klasse, die in der Lage ist, Multipart Form Data entsprechend zu parsen und bereitzustellen. Wichtg sind die Boundary's, die Content-länge und der HTML-Typische doppelte Zeilenwechsel (0d0a0d0a), sowie der einfache Zeilenwechsel am Ende eines Packets.

    Hoffe dass hilft dir ebbes weiter.
    Have some fun ...
    arni

    (PS Ein Sniffer ist hier seeehhr hilfreich beim Entwickeln(zb Ethereal))



  • Danke !!! soweit hab' ich alles verstanden.
    Ich bekomme den Header

    "-----------------------------264532080424877

    Content-Disposition: form-data; name="Datei"; filename="quasima.jpg"

    Content-Type: image/jpeg

    ÿØÿà"

    was ich allerdings noch nicht verstehe ist, wie ich nun an die anderen Parts komme. Wenn ich den stdin erneut abfrage, bleibt die Anwendung hängen.

    Gruß

    Robert



  • Die Dummheit hat mal wieder zugeschlagen und mich voll getroffen.
    Es hatte von anfang an funktioniert. Ich war nur zu blöd zu bemerken, dass meine zeichenkette natürlich nach einem '\0' unterbrochen wird aber tatsächlich weitergeht.

    Danke für die ausführliche Hilfe

    Gruß

    robert


Log in to reply