Binmode STDOUT
-
@Cardiac sagte in Binmode STDOUT:
header fields und values sind per rfc case-insensitive. jeder webserver der dir 500 wirft weil die header lower-case sind, kann einmal direkt in the muell.
Ja. Es gib eben Dinge die man einfach mal so hinnehmen muss weil sie so sind
MFG
-
um es vorweg zu nehmen: Das Problem liegt nicht in c++. Ein
binmode STDOUT
löst jedoch das Problem was ganz woanders liegt. Doch wo genau liegt denn nun das Problem?
Ich habe aufgrund eines Hinweis nun einen Hexdump erstellt. Dazu pipe ich die Ausgabe eines c++Program auf ein Perlscript, also über den Wegstdout/stdin
, untenstehend die c++ Source und Perl zum Nachvollziehen:int main(){ for( unsigned char c = 0; c < 256; c++){ cout << c; } return 0; }
while ( read(STDIN, my $c, 1) ){ printf "%02X\n", unpack "C", $c; }
Augeführt so
fw | c:\perl64\bin\perl.exe hexdump.pl | more > dump.txt
und siehe da, von 0x00 bis 0xFF ist alles angekommen. C++ gibt also die Binary korrekt aus.Das heißt, daß der
issue STDOUT
auf Win32 zwischen dem CGI-Prozess und dem ApacheWin32 zustandekommt. In dieser Versuchsanordnung ändert sich nichtsam Ergebnis, wenn ich im c++Programmbinmode STDOUT
einschalte. Was da genau auf dem Common Gateway (CGI) passiert, entzieht sich leider meiner Kenntnis. Entscheidend jedoch ist, daß es eine Lösung gibt.Viele Grüße!!
-
@_ro_ro sagte in Binmode STDOUT:
for( unsigned char c = 0; c < 256; c++){
Preisfrage: wann bricht diese Schleife ab?
-
sorry, falschen Code gestellt. Hier der Richtige
for( int i = 0; i < 256; i++){ unsigned char c = i; cout << c; }
Am Ergebnis ändert das nix
mfg
-
@_ro_ro sagte in Binmode STDOUT:
Du kannst dir die temporäre Variable sparen:std::cout << static_cast<unsigned char>( i );
-
@DocShoe sagte in Binmode STDOUT:
@_ro_ro sagte in Binmode STDOUT:
Du kannst dir die temporäre Variable sparen:std::cout << static_cast<unsigned char>( i );
Oh danke, ja werd' ich bestimmt noch öfter brauchen
Viele Grüße!!!PS: Heute Lötkolben statt Tastaur. Pünktlich zum Beginn der Fahrradsaison eben reingekommen:
PC Schaltnetzteil 12 V / 100 W
Damit läuft der Kompressor (der lag noch irgendwo rum). Damit Luftaufpumpen wieder Spaß macht
-
btw, bisher habe ich
// Percent Encodings unsigned char hex(string &hex){ unsigned char c; try{ size_t pos{}; c = stoi(hex, &pos, 16); } catch(std::invalid_argument const& ex){ throw string("stoi invalid argument"); } catch(std::out_of_range const& ex){ throw string("stoi ot of range"); } return c; };
was mir auch nicht so richtig gefällt. Aber der Cast zu
unsigned char
funktioniert. Verbessern oder so stehen lassen?Viele Grüße.
-
@_ro_ro
Eine Exception zu fangen und dann alsstd::string
neu zu werfen ist nicht gut. Wenn du nicht explizit jeden Exceptiontyp fangen einzeln willst kannst du einfachstd::exception
fangen, weil alle STL Exceptiontypen davon erben. Mitstd::exception::what()
kommst du dann an die Fehlermeldung.
Eigentlich brauchst du die ganze Funktion nicht, denn wenn duhex
aufrufst musst du Exceptions fangen, dann kannst du auch direktstd::stoul
aufrufen. Der zweite Parameter ist optional, wenn du den nicht auswerten möchtest kannst du auchnullptr
übergeben.unsigned char c = std::stoul( hex, nullptr, 16 );
Überspitzt gesagt macht deine Funktion genau das Gleiche wie
std::stoul
, nur dass sie eine schlechtere Fehlerbehandlung hat.
-
Die Frage ist aber, was passieren soll, wenn im Hexstring mehr als 2 Ziffern vorhanden sind, also soll z.B.
"ABCD"
als0xCD
zurückgegeben werden oder aber eine Exception werfen?
-
@Th69 sagte in Binmode STDOUT:
Die Frage ist aber, was passieren soll, wenn im Hexstring mehr als 2 Ziffern vorhanden sind, also soll z.B.
"ABCD"
als0xCD
zurückgegeben werden oder aber eine Exception werfen?Gute Frage
Jedoch kommt dieser Fall gar nicht vor. Die Prozentkodierung kodiert als%ff
genau ein Byte. Wenn der Parser ein Prozentzeichen findet, schickt er genau 2 Zeichen zum Decoder, nämlich die 2 Zeichen die rechts neben dem Prozentzeichen stehen.Und wie ich schon einmal schrieb, beim Provider läuft der Apache mit
mod_security
. Wenn da ein%ZZ
im Request ankommt, wird das mit Status 400 quittiert. Es ist nur so, daß ich diesen Status auf Perl umlege per.htaccess
und damit die Exception von C++ gar nicht zu sehen bekomme, weil die Antwort von Perl kommt.Lokal jedoch sehe ich die Exception, weil ich lokal kein
mod_security
installiert habe.MFG
-
@_ro_ro sagte in Binmode STDOUT:
Und wie ich schon einmal schrieb, beim Provider läuft der Apache mit
mod_security
. Wenn da ein%ZZ
im Request ankommt, wird das mit Status 400 quittiert. Es ist nur so, daß ich diesen Status auf Perl umlege per.htaccess
und damit die Exception von C++ gar nicht zu sehen bekomme, weil die Antwort von Perl kommt.Eine Anmerkung zu dem Gedankengang: Damit koppelst du dein Programm natürlich in gewisser Weise an Apache mit
mod_security
und die.htaccess
-Konfiguration, bzw. an ein vergleichbares Setup und reduzierst eventuell die Portabilität (hier: auf andere Webserver). Das kann man so machen, ich persönlich bevorzuge allerdings, wenn möglichst wenig Vorbedingungen erfüllt sein müssen, damit mein Programm korrekt funktioniert. Selbst wenn in dem Fall doppelt geprüft würde.
-
ja sicher doch braucht es eine eigene Apache-Konfiguration. Also eine
.htaccess
und die ist lokal wie remote dieselbe. Obmod_security
läuft oder nicht spielt in meiner Software überhaupt gar keine Rolle. Der Webserver muß nur wissen welche URLs nach Perl, PHP oder C++ geroutet werden und das regelt die Dateierweiterung.html | .chtml | .phtml
MFG
-
@_ro_ro
Ich denke, du hast @Th69 und @Finnegan da nicht richtig verstanden. Im Optimalfall sollte man Software wiederverwendbar machen, damit man das Rad nicht x-mal neu erfinden muss. In deinem Fall wirdhex
nur aufgerufen, wenn der string genau zwei Zeichen lang ist und nur gültige Hex-Ziffern enthält, weil der Webserver das sicherstellt. In einem anderen Kontext (anderes Projekt, anderer Webserver, was auch immer) ist das vielleicht nicht mehr der Fall, und dann funktioniert's halt nicht mehr. Wenn man das beim Schreiben der Funktion schon beachtet erlebt man später weniger Überraschungen.
-
@DocShoe sagte in Binmode STDOUT:
@_ro_ro
Ich denke, du hast @Th69 und @Finnegan da nicht richtig verstanden. Im Optimalfall sollte man Software wiederverwendbar machen, damit man das Rad nicht x-mal neu erfinden muss. In deinem Fall wirdhex
nur aufgerufen, wenn der string genau zwei Zeichen lang istStimmt. Von daher habe ich das auch geändert damit es evntl. woanders wiederverwendet werden kann:
int hex(string &hex){ int i; try{ i = stoi(hex, nullptr, 16); } catch(std::invalid_argument const& ex){ throw string("stoi invalid argument"); } catch(std::out_of_range const& ex){ throw string("stoi ot of range"); } return i; };
Und der Cast genau da wo er gebraucht wird:
// in Funktion percent_decode tokens << static_cast<unsigned char>( my::hex(hex) );
Danke nochmal und Viele Grüße!
-
@DocShoe sagte in Binmode STDOUT:
Wenn du nicht explizit jeden Exceptiontyp fangen einzeln willst kannst du einfach std::exception fangen, weil alle STL Exceptiontypen davon erben. Mit std::exception::what() kommst du dann an die Fehlermeldung.
Gute Idee!!! Danke und Gruß-
-
@_ro_ro sagte in Binmode STDOUT:
int hex(string &hex){
Durch so eine Funktionssignatur, also string&, zeigst du an, dass du den String per NICHT-konstanter Referenz übergibst - das bedeutet semantisch, dass du den String innerhalb deiner Funktion ändern willst. Du MUSST nun auch ein lvalue übergeben. Das heißt, das insbesondere sowas wie
hex("7F")
nicht funktioniert, weil das"7F"
keine Variable ist. Du müssteststring val = "7F"; hex(val);
schreiben.Da diese Funktion aber ihr Argument überhaupt nicht ändern soll, nutze
const
. Alsoint hex(const string &hex)
. Dasconst
ist mehr als nur Deko.
-
Danke, das hatte ich schlicht und einfach vergessen. Ist aber auch die fehlende Routine, kommt schon noch. Muss eh noch 'zig mal drüberschrubben
Viele Grüße--