CGI-Skript in C/C++ - Ärger mit File-Upload (multipart/form-data)
Andreas Bierhals
Hallo liebe HTML'ler!
Ich versuchte seit längerem, einen File-Upload mit einem
in C++ geschriebenen CGI-Skript zum laufen zu bringen, was
mir jetzt ENDLICH gelungen ist ;-)
Damit andere nicht in die gleiche Falle laufen, poste ich
das Problem vorbeugend mal ins Forum...
Ich hatte ein Formular mittels
<form action="http://...." method="post" enctype="multipart/form-data">
an mein CGI-prog geschickt, in dem sich u.a. auch ein
File-Button befindet, mit dem ein ASCII-File ge-uploadet
werden soll.
Mit folgendem C-Code Fragment wollte ich nun die geposteten
Daten aus der Standard-Eingabe stdin in den String 'post'
einlesen (um sie später weiterzuverarbeiten):
char *s, *post;
int postlen=0;
s=getenv("CONTENT_LENGTH");
// die Anzahl der ge-post-eten Zeichen in postlen speichern...
if (s!=NULL) postlen=atoi(s);
if (postlen>0) {
post = new char[postlen+1];
// postlen Zeichen aus stdin in post einlesen
fread(post, sizeof(char), postlen, stdin);
}
Funktionierte zunächst ohne Probleme, zumindest unter Win95 mit
dem Xitami-Server und dem OmniHTTPd.
Allerdings hat das Prog unter dem Personal Web Server und IIS von Microsoft
an dieser Stelle grundsätzlich gestreikt und verharrte in einer Art Endlosschleife.
Grund:
Die Funktion "fread(post, sizeof(char), postlen, stdin); " liest eigentlich
"postlen" Elemente der Größe "sizeof(char)" aus dem Eingabestrom "stdin"
in die Variable "post" ein - sollte man meinen...
Allerdings hat diese Funktion den Haken, daß sie bei Zeilenumbrüchen,
Will man nun aus stdin eine 1000 byte lange ASCII-Datei mit 50 Zeilenumbrüchen
lesen, so liefert fread(...) sämtliche Zeilen bereits nach 950 bytes
zurück (die fehlenden 50 bytes wurden ja durch die verkürzten Zeilenumbrüche
geschluckt).
Nun wurden aber 1000 Zeichen angefordert, aber "stdin" ist schon
nach 950 Zeichen mit seinem Latein am Ende!!
Als Resultat bleibt das Programm stehen und wartet endlos auf weitere Eingaben aus stdin,
bis der Web-Server sein Timeout erreicht und dem Programm den Gnadenstoß verpaßt.
Nachdem man dies weiß ($@§$%!!), kann man sich z.B. mit folgender Routine behelfen:
char *s, *post, *tmp;
int postlen=0;
s=getenv("CONTENT_LENGTH");
// die Anzahl der ge-post-eten Zeichen in postlen speichern...
if (s!=NULL) postlen=atoi(s);
// postlen Zeichen aus stdin in post einlesen
if (postlen>0) {
post = new char[postlen+1];
tmp = new char[postlen+1];
strcpy(post, "");
while(postlen>0) {
strcpy(tmp, "");
fgets(tmp, postlen+1, stdin);
postlen -= strlen(tmp)+1; // man beachte die +1 !!!
strcat(post, tmp);
}
}
die Funktion fgets(buffer, laenge, stream) liest dabei bis zum nächsten Zeilenumbruch
aber höchstens soviele Zeichen, wie in "laenge" angegeben wurde.
Viele Grüße!
Andreas
Hallo Andreas,
vielen Dank fuer Deine interessanten Hinweise!
Ich glaube zwar, nur eine Minderheit der Forumsbesucher ist mit C/C++ vertraut, und bei mir selber leuchteten bei der Lektuere auch nur einige undeutliche Erinnerungslichter tief im Hintergrund auf, aber hilfreich sind die Infos allemal.
Falls Du eine vollstaendige C-Routine zum File-Upload-Handling hast, kannst Du die ja gerne auch mal selber zum Download anbieten oder so...es sind immer viele Leute interessiert an so etwas, glaube ich.
viele Gruesse
Stefan Muenz
Hallo Stefan, hallo liebe HTML'ler!
Falls Du eine vollstaendige C-Routine zum File-Upload-Handling hast, kannst Du die ja gerne auch mal selber zum Download anbieten oder so...es sind immer viele Leute interessiert an so etwas, glaube ich.
Ich hab zwar jetzt eine File-Upload Routine, die auch unter Microsoft-Servern
zu funktionieren scheint. Allerdings weiß ich noch nicht, was jetzt
unter anderen Servern/Betriebssystemen passiert, wenn die Zeilenumbrüche
wieder anders gehandhabt werden.
Vermutlich existieren dazu sowieso schon
allgemeingültigere Routinen zum Download auf diversen Servern...
Wenn aber nach mehreren Tests unter verschiedenen Servern/Konfigurationen
alles zu funktionieren scheint, werde ich die Routine posten
oder zum Download bereitlegen...
Viele Grüße und frohe Festtage!
Andreas