non-blocking sockets - HTTP - Client-Seitig



  • Blockade schrieb:

    Dude wo ist dein Scheißproblem.

    Dein Duktus, dein Textverständnis oder deine Lernunwilligkeit. Eines von den Dreien. Such's dir aus.

    Blockade schrieb:

    Du hast selbst all die Nachteile der Content-Length aufgelistet.

    ... was?

    Es geht hier doch nicht um Chunked-Transfer vs. Content-Length. In der Hinsicht ist Chunked-Transfer noch um einige Ecken beschissener als Content-Length, weil du bei Chunked-Transfer Daten nicht einfach so dumpen kannst. Wenn ich bspw. einen HTTP-File-Server schreiben wollen würde, dann würde ich der Einfachheit und Schnelligkeit wegen sendfile (Linux) / TransmitFile (Windows) verwenden, weil ich mir so die Kopie von Kernelspace in Userspace (Lesen der Datei) und die Kopie von Userspace in Kernelspace (Schreiben der Datei in den Socket) spare.

    Glaubst du, bei Chunked-Transfer kommen die HTTP-Daten genauso rein, wie die Chunks aufgeteilt werden? Der erste read/recv also die HTTP-Header, und dann jedes Mal einen Chunk? Oder in der Richtung? Probier's aus. Würde mich sehr stark wundern, wenn das klappen sollte - dazu bräuchte der Kernel nämlich einen HTTP-Parser (und ja, ich weiß, dass MS ihren Parser bei IIS in den Kernel getan hat).

    Wenn ich sage, du sollst dich nicht auf Content-Length verlassen, dann aus den gleichen Gründen, aus denen du dich nicht auf die Länge in den Chunk-Headern verlassen solltest. Weil auch mal zu wenig oder zu viel ankommen kann. Warum, habe ich bereits erläutert. Das Prinzip ist vergleichbar bei Heartbleed gewesen - der Ping dort konnte größer sein als der Payload, und der Pong konnte dann (1 << 16) - 1 Bytes an Fremddaten beinhalten. Wenn du genug hast, breche ab. Sag recv nicht, wie viel HTTP-Daten du noch erwartest, sondern wie viel du noch speichern kannst.

    Blockade schrieb:

    Dass die Antwort vom Server geparst werden muss ist hier jedem klar.

    Ach?

    Blockade schrieb:

    ich muss entweder mit Timeouts arbeiten oder ich parse die Response Stück für Stück und hör halt dann auf, wenn alles angekommen ist.

    Hört sich für mich so an, als ob du nur eines machen wolltest, während ich gesagt habe, dass du beides machen musst.

    Blockade schrieb:

    Wie man das gleichzeitig anstellt (Chunk empfangen -> Parse-Routine wieder zum leben erwecken -> wiederhole) war hier die Frage.

    my_result_code mrc;
    
    do
    {
        /*Syntaxüberprüfung für Pipelining.*/
        mrc = my_http_syntax_checker();
    
        if(mrc == MY_RESULT_CODE_ERROR)
        {
            /*Muss abgebrochen werden.*/
        }
    
        if(mrc == MY_RESULT_CODE_OK)
        {
            /*Muss anders abgebrochen werden, ohne Rollback.*/
        }
    
        /*Sieht gut aus, wir können weitermachen.
        **Prüfe, ob wir Daten haben über select.*/
        if(select() == NO_DATA) /*Oder so, schau dir die Doku an.*/
        {
            /*Timeoutbehandlung/Abbruch*/
        }
    
        /*Jetzt können wir endlich vom Socket lesen*/
        recv();
    }
    while(1);
    

    my_http_syntax_checker muss dann natürlich allerhand prüfen. Und weil das blöd ist, packst du bei jedem Call ein Cache-Objekt rein, über das my_http_syntax_checker dann weiß, welche Teile bereits überspringen werden können.

    HTTP ordentlich zu parsen ist halt leider nicht trivial.



  • dachschaden schrieb:

    tntnet schrieb:

    Ich bekomme auf meinen Kommentar mit dem unbedachten Hinweis, dass ich so was schon mal gemacht habe und meine Lösung auch einsehbar ist die nächste Breitseite. Mein Code wäre schlecht.

    Das habe ich nicht geschrieben.

    Da mache ich mir die Mühe, lade deinen Code runter, schaue ihn mir ein bisschen an und mache Anmerkungen. Ich stelle Fragen. Das "Also so ganz überzeugt bin ich ja nicht ..." wäre die ideale Einleitung für dich gewesen - du schließt sie für dich ab mit einem Gefühlstrip. Anstatt darauf einzugehen - oder einfach nur zu sagen: "Ja, hast recht" - implizierst du, dass subjektive Kriterien wichtiger sind als objektive.

    Geht's noch?

    tntnet schrieb:

    Du erwartest jetzt wirklich, dass ich da anfange, meinen Code zu verteidigen?

    Nicht mehr. Die echte Chance dazu hattest du. Wegen deinem Ego-Trip hast du sie verspielt.

    tntnet schrieb:

    Wenn jemand echtes Interesse an meinem Code zeigt, bin ich gerne bereit, darüber zu diskutieren. Aber wenn ich so angegriffen werde, dass das doch alles sehr dürftig ist, dann lass ich es eben.

    Manchmal denke ich mir: so oft, wie du bei anderen Halluzinationen siehst - kann das nicht sein, dass du ihnen auch unterliegst?

    Aber das Gute an einem Forum ist, dass die Sachen da niedergeschrieben sind. Da kann man verlinken. Zitieren. Man kann noch mal seine eigenen Worte durchlesen.

    Also, ja, du halluzinierst gerade. Fett.

    Eine Beleidigung nach der anderen. Du fängst gleich damit an, dem Originalposter zu fragen, ob er Muttersprachler ist. Damit wirfst Du ihm vor, er würde schlechtes Deutsch schreiben. Und dann kommt dieses "deflate/gzip-Dekodierung wird nicht unterstützt? Denn de-chunken ohne weitere Kopie? ", welches völlig falsches Deutsch ist. So falsch, dass man es nicht mehr versteht. Anstatt zu sagen: "ach ja - war in der Hektik unverständlich formuliert", verteidigst Du das noch. Das nenne ich Ego-Trip.

    dachschaden schrieb:

    Habe mir mal den Code kurz angeschaut. Verwendet Streams zum Buffern, und die sind natürlich auch privat. Man kann also nicht eigenen Speicher angeben, der nach Möglichkeit noch erweitert werden kann. Relokation ist daher sehr wahrscheinlich auch mit einer Kopie verbunden.

    Das ist keine Frage, sondern eine Annahme, dass man keinen eigenen Speicher angeben kann, was Du offensichtlich für unabdingbar hälst. Das unterstützt den Eindruck, dass Du den Code offensichtlich nicht gut findest.

    Das sind keine interessierten Fragen und keine konstruktive Kritik sondern einfach nur Kritik oder Nörgelei.

    Der Satz "Also so ganz überzeugt bin ich ja nicht ..." ist keine ideale Einleitung sondern eine Herausforderung. Du hoffst, dass ich ein so großes Ego habe, dass ich da drauf springen muss.

    Ich reagiere nicht, indem ich mich verzweifelt erkläre, wie man es bei einem Ego-Trip machen würde, sondern lasse es einfach so stehen und akzeptiere das. Also genau das Gegenteil vom Ego-Trip, den Du mir vorwirfst.

    Du wirfst mir eine schlechte Arbeitseinstellung vor. Auch wieder offensichtlich mit dem Ziel, mich zu beleidigen. Das sieht wirklich nicht nach Interesse aus.

    Ok - Dann nehme ich mal an, Du willst wirklich wissen, was cxxtools so kann.

    Ja, es kann chunked decoding ohne Kopien. Es kann non blocking http requests über eine Event loop. Es prüft alle Fehlercodes von Systemaufrufen und reagiert darauf. Es reagiert anständig auf alle möglichen Fehlerzustände. Es kann reconnect. Es kann mit Servern umgehen, die sich nicht an Standards halten. Es geht selbst sehr pingelig mit Standards um. Du kannst beliebige Header setzen und auch im Result alle Header auslesen. Das Codebeispiel ist nur die einfachste Möglichkeit, einen HTTP-Request auszuführen. Will ich mehr, wird es natürlich ein wenig komplizierter. Das liegt in der Natur der Sache. Aber auch diese Interfaces sind keine Rocket-Science. Die Funktionalität ist also nicht, wie Du es annimmst "stark eingeschränkt".

    Alle Möglichkeiten aufzulisten würde hier zu weit gehen. Ach ja - gzip-Komprimierung kann er tatsächlich nicht. Das ist dann tatsächlich eine Einschränkung.

    Es gibt außerdem noch higher level interfaces wie z.B. xmlrpc, welches auch asyncron arbeiten kann. So kann ich in einer Eventloop mehrere xmlrpc-Request parallel ausführen oder in der gleichen Event loop noch einen (oder mehrere) xmlrpc-Server laufen lassen.

    Ach ja, und noch was: was ist an getaddrinfo Kaputt? Du schreibst so, als wüsste es jeder. Und was sind "Namenstabellen"?



  • tntnet schrieb:

    Eine Beleidigung nach der anderen.

    Nee, du weißt einfach nur nicht, was eine Beleidigung ist. Jemandem zu sagen, er halluziniert, ist keine Beleidigung - das ist normales, menschliches Verhalten. Ironischerweise sind gerade Leute mit einem großen Ego nicht in der Lage, dies zu akzeptieren - der Stolz verbietet es.

    "Hey, du riechst aus dem Mund!" - ist das eine Beleidigung? Nein, das passiert bei Menschen nun mal. Genau wie Halluzinationen. Jemand hat sich heute schon lächerlich gemacht, indem er mir unterstellt hat, dass Geisteskrankheit und Halluzination das gleiche sind. Geisteskrankheit bestimmt, wie du Sachen interpretiert. Halluzinationen beeinflussen, was für Sachen du siehst. Erste bestimmen die Verarbeitung, letztere die Eingabe. Und das gemeine ist, dass du es nicht mal sehen kannst. Die Chance ist ziemlich groß, dass du dir jetzt "Was für ein Unsinn!" sagen wirst - und dass du direkt in die Halluzination reinfällst. Für dich komplett logisch, aber von außen fragt man sich halt, was das soll.

    tntnet schrieb:

    Du fängst gleich damit an, dem Originalposter zu fragen, ob er Muttersprachler ist. Damit wirfst Du ihm vor, er würde schlechtes Deutsch schreiben.

    Ist das nicht evident? Oder soll das wieder eine Beleidigung sein?

    Auch hier wieder Halluzination. Du siehst etwas, weil dein Ego es sehen will. Er verwendet einen Begriff, der da nicht reingehört. Von dem er nicht weiß, was er bedeutet. Warum tut er das nicht? Ist er Muttersprachler oder nicht? Soll ich Nachsicht haben oder nicht?

    Meinen Onkel hat man mal gefragt, ob er überhaupt der deutschen Sprache mächtig ist. Er ist ebenfalls Muttersprachler. In der Frage ist keine Beleidigung drin, sondern höchstens die Aufforderung, dass man deutlicheres Deutsch sprechen könnte. Da das Ego aber einen halluzinieren lässt, ignoriert man diese Aufforderung, und interpretiert die Ehrverletzung als Beleidigung.

    Ist es das, worum es dir geht? Dass ich für dich Nichtmuttersprachler geschliffenes Deutsch schreiben soll? Das kann ich ja machen. Aber dann hör auf, zu behaupten, dass das völlig falsches Deutsch sein soll. Ist es nicht. Der Post mit Hauptsatz und Nebensatz ist zwar stilistisch übertrieben, aber dennoch faktisch korrekt. Wenn du es nicht verstehen solltest, dann sag es doch, und dann verwende ich vollständig ausgeschriebene Sätze. Oder wir können direkt in Englisch kommunizieren. Ich habe da keine Ängste.

    tntnet schrieb:

    Das nenne ich Ego-Trip.

    Weißt du, das könnte man annehmen - wenn ich von dir jemals Argumente gehört hätte, die über ein "Du hast aber unrecht!!1!" hinausgehen würden. Ich habe bereits auf Haupt- und Nebensätze verwiesen und erklärt, wieso das Verb im Nebensatz fehlen darf. Wenn das falsch sein sollte, dann widerlege sie bitte.

    Was du mir wohl vorwerfen kannst, ist, dass ich nicht den offiziellen Namen "Satzwertige Ausdrücke" verwendet habe. Aber das ist weit von "in der Hektik unverständlich formuliert" entfernt.

    tntnet schrieb:

    Das ist keine Frage, sondern eine Annahme, dass man keinen eigenen Speicher angeben kann, was Du offensichtlich für unabdingbar hälst.

    1. Hältst.
    2. Habe ich das bereits auch geschrieben:

    dachschaden schrieb:

    Da mache ich mir die Mühe, lade deinen Code runter, schaue ihn mir ein bisschen an und mache Anmerkungen.

    Natürlich sind das Annahmen. Sind sie falsch? Ich habe bisher noch nicht weitergelesen. Was ich sehe, sind die Konstruktoraufrufe der Objekte.

    Unabdingbar ist die Angabe von eigenem Speicher nicht. Es ist lediglich ein Qualitätsmerkmal, welches du selbst in der C-Standardlib findest (dass man also einen Buffer mitgeben kann/soll, in den reingeschrieben wird). Meine persönliche Erfahrung war, dass ich als Anfänger gar nicht verstanden habe, warum man immer Speicher angeben soll. Das soll die Sprache doch für mich machen!!1!

    Erst mit der Zeit ist mir aufgefallen, dass die Leute hinter dem Interface ein paar Sachen wussten, die ich nicht wusste. Z.B. dass Speicherreservierung teuer ist. Dass man mir die Chance geben will, meinen eigenen Speicher anzugeben, weil die Programmierer mich für schlau genug halten, dass ich weiß, was ich tue. Und das ist die Philosophie von C - dass ich weiß, was ich tue. Wenn ich's nicht tue, soll ich eine andere Sprache verwenden. Die Schnittstelle wurde so gebaut, dass ich mündig mit ihr arbeiten kann, anstatt dass ich unmündig davor sitze, weil alles für mich ohne meinen Willen erledigt wird. Ja, es ist im Grunde ein Kampf um die eigene Aufklärung. Ich will einen Default, aber immer die Möglichkeit haben, einzugreifen.´

    Und wenn du diese Möglichkeit nicht bietest, dann aus drei Gründen:

    1. du möchtest bewusst nicht, dass der Programmierer aufgeklärt ist (Friss oder stirb!).
    2. du möchtest dir nicht die Mühe machen.
    3. du erkennst die Problematik nicht.

    Ich unterstelle dir keine Böswilligkeit, deswegen würde ich für 2 und/oder 3 plädieren - aber das Problem wird ja dadurch auch nicht gelöst.

    tntnet schrieb:

    Der Satz "Also so ganz überzeugt bin ich ja nicht ..." ist keine ideale Einleitung sondern eine Herausforderung. Du hoffst, dass ich ein so großes Ego habe, dass ich da drauf springen muss.

    Hoffnung war dabei, aber eher darauf, selbst etwas bei lernen zu können.

    tntnet schrieb:

    Ich reagiere nicht, indem ich mich verzweifelt erkläre, wie man es bei einem Ego-Trip machen würde, sondern lasse es einfach so stehen und akzeptiere das. Also genau das Gegenteil vom Ego-Trip, den Du mir vorwirfst.

    Und hier ist sie wieder, die Halluzination.

    Egos können sich auf mehrere Arten manifestieren. Entweder, indem man sämtliche Kritik nicht an sich heranlässt (was du getan hast - oder zumindest hast du so gewirkt), oder indem man den anderen niedermacht, mit oder ohne Beispiele:

    "Dummkopf. Du hast keine Ahnung, wovon du redest. Schau dir xxx.cpp, Zeile 23 - 42. Da hast du dann de-chunken ohne Kopie! Einen solchen Analphabeten habe ich ja noch nie getroffen."

    Was ich erwartet hätte? Ganz ehrlich?

    "http_state.c. Da werden die Sachen geparst. Studium überlasse ich dir."

    Nix Ego. Keine Herabsetzung. Hier sind die Fakten, bamm, bamm, bamm, keine Zeit für irgendeinen Blödsinn. Nur weil du nicht auf der anderen Seite des Spektrums warst, heißt das nicht, dass du in der Mitte warst.

    tntnet schrieb:

    Du wirfst mir eine schlechte Arbeitseinstellung vor.

    Noch einmal, soll ich von Böswilligkeit ausgehen?

    tntnet schrieb:

    Auch wieder offensichtlich mit dem Ziel, mich zu beleidigen. Das sieht wirklich nicht nach Interesse aus.

    Also ist es dir lieber, das Evil Genius zu sein?

    tntnet schrieb:

    Es reagiert anständig auf alle möglichen Fehlerzustände.

    Was ist "anständig"?

    tntnet schrieb:

    Aber auch diese Interfaces sind keine Rocket-Science. Die Funktionalität ist also nicht, wie Du es annimmst "stark eingeschränkt".

    OK, nehmen wir mal an, dass ich den gleichen Speicher für den temporären HTTP-Request-String und den schlussendlichen Response verwenden möchte, wie ich schon beim Durchgehen der Prozessliste und dem Einladen einer Konfigurationsdatei verwendet habe? In der Regel habe ich bei sowas bereits vier 2-MiB-Pages reserviert, die ich gerne weiterverwenden würde. Und wenn noch mehr Speicher zum Schreiben der Daten verwendet wird, soll sich der Speicher noch weiter erhöhen können.

    Das sind kein konstruierter Fall - das habe ich schon öfter schreiben müssen. Vielleicht habe ich hier nur hohe Standards, aber wenn ich das nicht ohne Verrenkungen machen kann, dann ist das Interface für mich nun mal stark eingeschränkt.

    tntnet schrieb:

    Ach ja, und noch was: was ist an getaddrinfo Kaputt? Du schreibst so, als wüsste es jeder. Und was sind "Namenstabellen"?

    1. Sagen wir mal, ich möchte nur einen, oder zwei, oder drei Hosts maximal haben. Mein naives C-Gehirn sagt mir, dass ich dafür (für das Abspeichern) drei Parameter brauche:

    - den Buffer, in dem die Objekte geschrieben werden.
    - Anzahl an Elemente, die maximal reingeschrieben werden können.
    - Zeiger auf eine Variable, die die Anzahl aller geschriebenen Elemente erhält.

    (den ganzen anderen Quatsch mit den hints und node und so weiter lassen wir mal komplett außer Acht. Den dritten Parameter könnte man in einen In-Out-Parameter verwandeln - sprich, er muss gesetzt sein, und wird dann selbst von der Funktion neu gesetzt, aber das empfand ich immer als hässlich. Da kann man aber drüber streiten).

    So - mit dieser Art der Namensauflösung habe ich einen Funktionsaufruf, und kann selbst entscheiden, was mit dem Speicher passieren soll. Verwende ich ihn wieder? Liegt er nur auf dem Stack rum und wird gleich eh wieder entfernt?
    Durch die Elemente kann ich wie durch ein Array iterieren, und weil die Elemente nebeneinanderliegen, erhalte ich außerdem Cache-Lokalität.

    Oh, aber was ist, wenn es noch ganz viele mehr mögliche Adressen für den Namen gibt?

    Meine "spontane" Lösung dafür ist nicht optimal, aber OK: eine andere Funktion schaut im DNS-Cache nach oder macht noch mal einen Lookup, und dann sind sie auch im Cache. Und dann gibt sie mir die Anzahl der Einträge zurück, die sie gefunden hat.

    Und dann kann ich wieder selbstständig Speicher reservieren und verwalten, anstatt das an eine mir unbekannte Funktion zu delegieren.

    2. Sagen wir mal, ich verwalte zwei HTTP-Objekt - wie in Perl User Agents oder so änlich - und beide haben ein bestimmtes Set von Requestdaten (andere Methode, Header, Version, egal). Sie haben auch eine Reihe von aufgelößten Namen, mitunter sogar noch verbundene Sockets, auf verschiedenen Ports, mit verschiedenen Protokollen.

    Naiv würde ich diese Daten in ein privates Array oder Vektor oder so tun (auch hier kann ich wieder mit dem Speicher rumspielen, aber halten wir's mal einfach).

    Jetzt will ich mit einem User Agent einen Request an einen Host schicken, der bereits bei einem anderen User Agent bekannt ist. Ich weiß sogar, welcher User Agent das ist. Ich kann jetzt manuell zwischen den beiden vermitteln, aber lieber wäre mir, wenn sie ihre Namenstabellen (oder Verbindungslisten, oder wie du sie auch nennen willst) teilen und synchronisieren würden. Dann müsste ich nicht mal mehr einen Round-Trip zum DNS-Cache auf mich nehmen, sondern könnte mich einfach darauf verlassen, dass die User Agents so viel wie möglich wiederverwerten.



  • dachschaden schrieb:

    tntnet schrieb:

    Eine Beleidigung nach der anderen.

    Nee, du weißt einfach nur nicht, was eine Beleidigung ist.

    Warum schlägst du es nicht mal nach und lenkst nicht durch Anderes ab? Weil du ja Wikipedia so magst Beleidigung (Psychologie) (die Argumentation funktioniert im Wesentlichen auch, wenn wir den juristischen Begriff zugrundelegen würden, der ist aber u.U. zu eng gefasst, um als Grundlage sozialer Normen (Netiquette) geeignet zu sein):

    Eine Beleidigung ist eine Aussage oder Handlung eines Senders, die das Ego bzw. den Stolz eines Empfängers mit negativen Emotionen assoziiert – der Kränkung – und somit herabwürdigt.

    Das Erste, was auffallen muss, ist, dass es auf den Wahrheitsgehalt der Aussage nicht ankommt. Das Wie, Warum und Wann (Kontext!) kann erheblich wichtiger sein. Das Beleidigung kann sich auch aus dem, was nicht gesagt aber impliziert wird, ergeben. Auch muss die Beleidigung nicht unbedingt in der Absicht des Senders liegen, sondern kann auf einem Missverständnis beruhen.

    dachschaden schrieb:

    Jemandem zu sagen, er halluziniert, ist keine Beleidigung

    Es kann eine Beleidigung sein. Insbesondere (aber nicht ausschlieslich, s.o.) dann, wenn diese Behauptung nicht durch durch entsprechende Beobachtungen gedeckt sind.

    dachschaden schrieb:

    "Hey, du riechst aus dem Mund!" - ist das eine Beleidigung? Nein, das passiert bei Menschen nun mal.

    Ja, das passiert, und wenn das Arzt sagt oder eine andere Person im Vertraulichen kann das völlig in Ordnung sein. Wenn aber jemand mit dem Megafon durch die Strassen geht und so etwas von sich gibt, sieht die Sache eben ein bisschen anders aus.

    dachschaden schrieb:

    Jemand hat sich heute schon lächerlich gemacht, indem er mir unterstellt hat, dass Geisteskrankheit und Halluzination das gleiche sind.

    Nenn doch ruhig Namen, wenn du meinst, das wäre so gewesen und müsste hier unbedingt nochmal ausgebreitet werden. Aber vielleicht bist du auch selbst gar nicht davon überzeugt, brauchst es um dein Ego zu streicheln, möchtest aber nicht, dass sich jemand die Mühe macht, und nachschaut, ob das tatsächlich gesagt wurde.

    Falls das zu schwer war, nehme ich es nochmal für dich auseinander:
    Jemandem hier in einer Antwort - ohne erhebliche Evidenz in dieser Hinsicht - zu unterstellen, er würde halluzinieren, muss beleidigend wirken. Denn die bloße Äußerung impliziert, dass diese Evidenz in dessen vorheriger Aussage zu finden ist. Diese vorherige Aussage ist aber nicht das direkte Resultat der Sinneswahrnehmungen des Authors, sondern ein Produkt seine Geistes, und weil ja das Halluzinieren des Authors angeblich so offensichtlich ist, kann es um dessen Geistesverfassung nicht so gut gestellt sein, schliesslich bedeutet das sinnliche Wahrnehmen von Dingen, die nicht existieren, nicht zwingend, dass man sich dieser Täuschung nicht rational bewusst werden kann.
    Nun ist halluzinieren ein Wort mit einer recht klar umrissenen Bedeutung, die auf ein bestimmtes klinisches Erscheinigungbild verweist. Das bedeutet umgekehrt, dass die Verwendung eine starke Abwertung bedeutet in einem Kontext wie etwa diesem Forum, in dem nur ein sehr oberflächlicher Kontakt - und somit keine gesicherte Diagnose - möglich ist. Dabei gibt es ja durchaus Synonyme, wie etwa irren oder täuschen, die diese extreme Abwertung nicht enthalten. Da du dich trotzdem auf diese Vokabel festlegst (mangelnde Sprachkenntnis scheint ja nicht das Problem zu sein), schlussfolgere ich, dass die Beleidigung tatsächlich auch bewusst und gewollt ist.

    Nebenbei bemerkt war mein vorheriger Beitrag, auf den der Halluzinationsvorwurf erfolgt, primär ein Werturteil und damit (mangels absoluten Wahrheitsgehaltes, da abhängig von Wertmaßstäben) nicht mal abstrakt geeignet, Halluzinationen zu belegen. Es sei denn, du bist tatsächlich der Ansicht, dein Verhalten könnte unter keinen Umständen oder Maßstäben kritikwürdig sein. In diesem Fall entbehrte der Halluzinationsvorwurf nicht einer gewissen Ironie.



  • SeppJ warum greifst du hier komischerweise nicht ein?



  • camper schrieb:

    ...

    Danke. Mehr sage ich dazu nicht mehr.

    Und jetzt zum Thema. Ich gehe mal weiterhin davon aus, dass die Verarbeitung von HTTP-Requests interessant ist.

    Erst mal: der Parser ist in der Datei src/http/parser.cpp zu finden.

    Dieses Vorgeben von Speicher halte ich nicht für die richtige Lösung. In aller Regel benötige ich die Daten, die vom Server kommen eben nicht vollständig aufeinanderfolgend im Speicher. Idealerweise schreibe ich einen stateful Parser, welcher Byte für Byte vom Server liest und darauf durch Zustandsübergänge reagiert. Dadurch brauche ich zu keinem Zeitpunkt den vollständigen Request im Speicher zu halten.

    Dafür ist std::streambuf gedacht. Da kann ich Byteweise lesen und wenn ich das nächste Byte brauche, bekomme ich es entweder aus dem Puffer oder der Streambuf holst sich den nächsten Block.

    Im Falle von cxxtools bedeutet das je nach http reply, dass die nächsten Daten entweder direkt vom Socket gelesen werden oder dass noch ein chunkedreader (src/http/chunkedreader.cpp) noch dazwischen ist, der eben genau so arbeitet.

    So kann sich beispielsweise der xmlrpc client in cxxtools ganz darauf konzentrieren, den xmlrpc Request zu parsen und braucht sich nicht darum zu kümmern, dass die Daten möglicherweise nicht am Stück kommen.

    Oder will ich den Reply body auf std::cout ausgeben, ist das ok, wenn ich immer Stückchenweise lese und auf cout ausgebe. Das ist nicht so schwer und kommt vollständig mit kleinen Puffern aus ohne dass zwischendurch Allokationen statt finden.

    Ich habe jetzt verstanden, dass Du (Dachschaden, keine Beleidigung 😃 ) getaddrinfo für unglücklich hälst. Ja im prinzip ist immer das Problem, dass es kein asyncrones Interface to getaddrinfo gibt. Ich glaube, dass an dieser Stelle cachelokalität gar nicht so ins Gewicht fällt, da hier andere Dinge deutlich teuerer sind.

    Im Falle von cxxtools gibt es eine Trennung zwischen client und request. Idealerweise habe ich ein Client-Objekt, welches ich länger halte. Dadurch wird der Verbindungsaufbau inklusive Namensauflösung nur ein mal gemacht. Die Verbindung wird dann für mehrere Request wieder verwendet.

    Du hast auch noch erwähnt, dass chunked encoding schlecht ist, weil man dadurch kein sendfile verwenden kann. Das schöne ist, dass der Server entscheiden kann, was für den Anwendungsfall geeignet ist. Liegen die Daten im Dateisystem, kann einfach ein Content-Length gesendet werden und dann mit sendfile die Daten. Werden die Daten so nach und nach produziert, kann der Server sich dagegen für chunked encoding entscheiden, so dass er am Anfang nicht wissen muss, wie viele Daten noch kommen.

    Du wolltest noch wissen, was es in cxxtools bedeutet, "anständig" auf Fehler zu reagieren. cxxtools wirft im Falle von Fehlern exceptions. Ich könnte jetzt noch darüber schreiben, wie praktisch Exceptions sind und wie elegant man damit robuste Programme schreiben kann, aber darüber wurde schon so viel geschrieben.

    Und noch was @Blockade (wieder keine Beleidigung sondern der Originalposter 🙂 ): Auf Content-Length kann man sich doch verlassen. Das gehört zum Protokoll. Wenn der Server weniger Daten schickt, dann ist der Reply noch nicht vollständig. Wird dann der Socket geschlossen, dann ist das eben ein Fehler. Schickt er mehr, dann gehören die folgenden Daten eben nicht zum reply sondern sind eventuell schon der nächste reply wenn ich mehrere Requests gleichzeitig geschickt habe.



  • tntnet schrieb:

    Und noch was @Blockade (wieder keine Beleidigung sondern der Originalposter 🙂 ): Auf Content-Length kann man sich doch verlassen. Das gehört zum Protokoll. Wenn der Server weniger Daten schickt, dann ist der Reply noch nicht vollständig. Wird dann der Socket geschlossen, dann ist das eben ein Fehler. Schickt er mehr, dann gehören die folgenden Daten eben nicht zum reply sondern sind eventuell schon der nächste reply wenn ich mehrere Requests gleichzeitig geschickt habe.

    Jo, kann man drüber streiten.

    Du gehst halt davon aus, dass der Server verdammt ehrlich mit dir ist, und dass du seinen Headern traust. Erfahrungsgemäß kann ich aber sagen, dass 1. die Content-Length nicht dabei sein musst (wobei du dann Fallunterscheiden musst und die Response auf nem Umweg kriegen musst) oder die Content-Length einfach nicht korrekt ist und du dann nicht alles oder zu viel empfängst (was bei zu viel+blocking dann in einem Block-Call enden würde).

    Content-Length's find ich gut für Ladebalken und so. Da kanns ruhig um einen Byte ungenau sein oder so. Aber sonst will ich mich doch eher auf meinen eigenen Code verlassen, als auf die Header der Antwort vom Server.



  • Offtopic-Bullshit, mein zweiter Post ist wieder on-topic:

    camper schrieb:

    Warum schlägst du es nicht mal nach und lenkst nicht durch Anderes ab?

    In deinem Fall würde dann die "Beleidigung" umschlagen in eine Situation, in der sich die "Linken" (sowohl Deutschland als auch die U.S.A.) über einzelne Wörter echauffieren. "Did you just assume my gender?" hört sich erst mal wie ein netter Scherz an, bis man sich vergegenwärtigt, dass es Leute gibt, die bereits dadurch beleidigt sind, dass man ihr physikalisches Geschlecht benannt hat.

    Und für so 'ne Kinderkacke habe ich wieder Zeit noch Bock. Wenn mir jemand sagt, da und da stinkt mein Code, dann danke ich ihm - wenn die Vorwürfe stimmen. Wenn mir jemand sagt, ich stinke aus dem Mund, dann entschuldige ich mich und versuche, den Geruch zu entfernen/übertünchen. Vielleicht mag es bei dir angebracht sein, den Boten zu erschießen - aber ich mache das nur dann, wenn der Bote Unsinn erzählt.

    camper schrieb:

    Das Erste, was auffallen muss, ist, dass es auf den Wahrheitsgehalt der Aussage nicht ankommt. Das Wie, Warum und Wann (Kontext!) kann erheblich wichtiger sein.

    Viele Menschen ordnen das so ein, ja.

    Viele Menschen leben auch in einer Blase, in der Sachverhalte schön konsistent bleiben. Und wenn neue Sachverhalte reinkommen, die die alten invalidieren, dann wird zurückgefeuert. Backfire-Effekt, halt.

    Mit sowas halte ich mich nicht auf, sorry. Wenn du dadurch beleidigt wirst, dass ich deinem Code ein negatives, aber objektiv nachvollziehbares Attribut zuweise, welches nicht nur darauf abzielt, die Person anzugreifen ("Was für ein undurchsichtiger Scheißcode"), dann solltest du künftig keinen Code mehr veröffentlichen. Das ist das Beste für uns und für dein Ego.

    camper schrieb:

    Das Beleidigung kann sich auch aus dem, was nicht gesagt aber impliziert wird, ergeben. Auch muss die Beleidigung nicht unbedingt in der Absicht des Senders liegen, sondern kann auf einem Missverständnis beruhen.

    Deswegen gibt es das Konzept der Nachfrage.

    camper schrieb:

    Es kann eine Beleidigung sein. Insbesondere (aber nicht ausschlieslich, s.o.) dann, wenn diese Behauptung nicht durch durch entsprechende Beobachtungen gedeckt sind.

    OK, dann denk' dir mal folgenden Sachverhalt:

    - ich sage "X".
    - du sagst, ich hätte "XYZ" gesagt.
    - ich sage, du halluzinierst.

    Jetzt kann es natürlich sein, dass ich nur halluziniert hätte, dass du "XYZ" gesagt hast - aber wenn das so ist, warum hast du dann bisher kein konkretes Beispiel benannt? In diesem Thread oder in dem anderen? Stattdessen geht es hier um Meinungen. Meinungen kann man in der "Jenseits der Programmierung"-Sektion loswerden. Gib mir harte Fakten.

    Juristisch ist nämlich Beleidigung definiert:

    Die Beleidigung trotz Wahrheitsbeweis: Eine solche liegt vor, wenn trotz einer Kundgabe wahrer Tatsachen gegenüber Dritten den Betroffenen gewissermaßen "an den Pranger stellen" würde, d.h. bei der Behauptung inhaltlich ein besonders herabwürdigender Tonfall oder eine besonders gehässige Einkleidung feststellbar wäre.

    Im Grunde also, wenn ich eine systematische Rufschädigung betreibe. Alles andere ist Verleumdung (bewusstes Verbreiten der Unwahrheit) oder üble Nachrede (Verbreiten von Informationen, die sich später als falsch herausgestellt haben).

    Stelle ich hier Leute an den Pranger? Nee, die Leute stellen sich selbst an den Pranger, schließlich ist das hier ein öffentliches Forum. Ich verwalte hier keine Liste oder dergleichen, ich stelle hier nicht die Unwahrheit da. Was ich mache, sind potentielle Ehrverletzungen, basierend auf Tatsachen.

    Jetzt kommen wir mal zu:

    camper schrieb:

    Ja, das passiert, und wenn das Arzt sagt oder eine andere Person im Vertraulichen kann das völlig in Ordnung sein. Wenn aber jemand mit dem Megafon durch die Strassen geht und so etwas von sich gibt, sieht die Sache eben ein bisschen anders aus.

    Siehe oben. Megafon wäre Pranger. In der Öffentlichkeit neben jemandem zu sitzen und zu sagen, dass er aus dem Mund riecht, ist allerhöchstens ehrverletzend. Offence is taken, not given.

    camper schrieb:

    Nenn doch ruhig Namen, wenn du meinst, das wäre so gewesen und müsste hier unbedingt nochmal ausgebreitet werden.

    Ne, das wäre ja Leute an den Pranger stellen. Das tue ich nicht. 😃

    camper schrieb:

    Aber vielleicht bist du auch selbst gar nicht davon überzeugt, brauchst es um dein Ego zu streicheln, möchtest aber nicht, dass sich jemand die Mühe macht, und nachschaut, ob das tatsächlich gesagt wurde.

    Es gibt da unter dem Benutzernamen bei jedem Post einen Link, der nennt sich "Benutzerprofil". Da kannst du draufklicken, und in dem Formular gibt es dann die Funktion "Alle Beiträge von dachschaden anzeigen".

    Wenn jemand es rausfinden wollen würde, dann tut er dies auch. Ist ja schließlich öffentlich hier. Nochmal: dass ich hier nicht Leute an den Pranger stelle, ist die Voraussetzung dafür, dass keine Beleidigung im Spiel ist.

    camper schrieb:

    Falls das zu schwer war, nehme ich es nochmal für dich auseinander:
    Jemandem hier in einer Antwort - ohne erhebliche Evidenz in dieser Hinsicht - zu unterstellen, er würde halluzinieren, muss beleidigend wirken.

    Falls das zu schwer war, nehmen ich es nochmal für dich auseinander:
    Zitierung auf zuvor getätigte Aussagen, die in starkem Kontrast zu einer Rekapitulation sind, sind "erhebliche Evidenz" und sollten zumindest einer Rechtfertigung oder einer Erklärung folgen. Wenn dies nicht geschieht, ist das kein Fall von Beleidigung, sondern lediglich kognitive Dissonanz, weil ich dich darauf hingewiesen habe, dass dein Selbstbild nicht mit den Tatsachen übereinstimmt.

    Keine Beleidigung.
    Keine Verleumdung.
    Keine üble Nachrede.

    Zu behaupten, dass da keine Evidenz wäre, ist keine Evidenz. Das ist wiederum eine Halluzination.

    camper schrieb:

    Denn die bloße Äußerung impliziert, dass diese Evidenz in dessen vorheriger Aussage zu finden ist.

    Hast du dir überhaupt mal den Thread durchgelesen? Was glaubst du, warum ich immer die Aussagen zitiere, auf die ich mich beziehe? Sogar mit Fettdruck?

    camper schrieb:

    Diese vorherige Aussage ist aber nicht das direkte Resultat der Sinneswahrnehmungen des Authors, sondern ein Produkt seine Geistes, und weil ja das Halluzinieren des Authors angeblich so offensichtlich ist, kann es um dessen Geistesverfassung nicht so gut gestellt sein, schliesslich bedeutet das sinnliche Wahrnehmen von Dingen, die nicht existieren, nicht zwingend, dass man sich dieser Täuschung nicht rational bewusst werden kann.

    Es ist zugegebenermaßen schwer, Müll in der Ausgabe daran zu erkennen, ob nur die Eingabe Müll war, oder ob die Verarbeitung kaputt ist. Wenn es allerdings ein Log (Forumsbeiträge) darüber gibt, welche Eingaben getätigt wurden, und dies in Verbindung zu den geäußerten Eindrücken setzt, dann erkennt man, dass (innerhalb der Eingabe) die Handlung des Autors rational ist. Wenn man zu "Statement 1, Statement 2, dein Code überzeugt mich nicht wirklich" ein "Dein Code ist schlecht" macht, dann wird klar, warum der Autor so handelt, wie er handelt.

    Nur dass sich der Autor halt mit falschen Informationen füttert. Müll rein => Müll raus.

    camper schrieb:

    Nun ist halluzinieren ein Wort mit einer recht klar umrissenen Bedeutung, die auf ein bestimmtes klinisches Erscheinigungbild verweist. Das bedeutet umgekehrt, dass die Verwendung eine starke Abwertung bedeutet in einem Kontext wie etwa diesem Forum, in dem nur ein sehr oberflächlicher Kontakt - und somit keine gesicherte Diagnose - möglich ist.

    Warum hast du hier nicht mal die Wikipedia-Seite konsultiert, bevor du Schwarm verbreitest?

    Wikipedia schrieb:

    Unter Halluzination versteht man eine Wahrnehmung, ohne dass eine nachweisbare externe Reizgrundlage vorliegt. Solche Wahrnehmungen können in jedem Sinnesgebiet auftreten. Das bedeutet zum Beispiel, dass physikalisch nicht nachweisbare Objekte gesehen oder Stimmen gehört werden, ohne dass jemand spricht. [...] Von der Halluzination zu unterscheiden ist die Wahnwahrnehmung. Dabei wird einer realen, also auch von anderen nachzuvollziehenden Wahrnehmung eine wahnhafte Bedeutung zugemessen. Ein Beispiel hierfür wäre, wenn jemand fest davon überzeugt ist, dass das zufällige Läuten einer Kirchenglocke ein Signal an seine Verfolger darstellt, ihn jetzt zu ergreifen.

    Ich habe nicht gesagt, "du bist wahnsinnig" - ich habe gesagt "du halluzinierst". Weil man für eine solche Diagnose die ursprüngliche Aussage und das, was beim Empfänger angekommen ist, nebeneinander benötigt. Das hat tntnet getan. Case closed, es sei denn, du hast Belege dafür, dass ich wiederum halluziniere.

    Wikipedia schrieb:

    Dabei gibt es ja durchaus Synonyme, wie etwa irren oder täuschen, die diese extreme Abwertung nicht enthalten.

    Irrtum befasst sich meines Verständnisses nach eher mit der Verarbeitung aufgrund von falschen Informationen, wie auch die Wikipedia-Seite aufzeigt:

    Wikipedia schrieb:

    Der Irrtum bezeichnet im engeren Sinne eine falsche Annahme oder Meinung oder einen falschen Glauben, wobei der Behauptende, Meinende oder Glaubende jeweils das Falsche für richtig hält. Im Gegensatz zu einer Lüge, bei der die Wahrheit bewusst verfälscht worden ist, entsteht ein Irrtum unabsichtlich aus falschen Informationen oder Fehlschlüssen.

    Im weiteren Sinne wird der Begriff des Irrtums auch auf falsche Behauptungen und andere fehlerhafte Handlungen angewandt, die aus einer irrigen Annahme oder einem falschen Glauben resultieren.

    Ich will mich allerdings auf die Wahrnehmung an sich beziehen, nicht die falschen Schlüsse (Irrtümer), die dadurch entstehen. Ursache und Symptom. Leicht zu unterscheiden.

    camper schrieb:

    Nebenbei bemerkt war mein vorheriger Beitrag, auf den der Halluzinationsvorwurf erfolgt, primär ein Werturteil und damit (mangels absoluten Wahrheitsgehaltes, da abhängig von Wertmaßstäben) nicht mal abstrakt geeignet, Halluzinationen zu belegen.

    Ist in Ordnung. Red' dir das ruhig ein. Was immer dich besser schlafen lässt.



  • tntnet schrieb:

    Erst mal: der Parser ist in der Datei src/http/parser.cpp zu finden.

    Hm.

    chartoprint erstellt ein Stringobjekt - warum ich das nicht gut finde, habe ich bereits erläutert.

    Die Prüfungsfunktionen ( istokenchar , isHexDigit ...) in http zu packen finde ich merkwürdig. Bei mir habe ich die in einem "zentralerem" Modul.

    Dein Stil macht bei mir irgendwie den Eindruck, als ob du mit der Grammatik haderst - hier mal ein Beispiel:

    void HeaderParser::state_qparam(char ch)
    {
        if (ch == ' ' || ch == '\t')
        {
            log_debug("queryString=" << token);
            ev.onUrlParam(token);
            token.clear();
            token.reserve(32);
            state = &HeaderParser::state_protocol0;
            return;
        }
        else
        {
            token += ch;
            return;
        }
    }
    

    Warum machst du da nicht direkt:

    void HeaderParser::state_qparam(char ch)
    {
        if (ch != ' ' && ch != '\t')
        {
            token += ch;
            return;
        }
    
        log_debug("queryString=" << token);
        ev.onUrlParam(token);
        token.clear();
        token.reserve(32);
        state = &HeaderParser::state_protocol0;
    }
    

    Nur mal so als Beispiel.

    Den Stateful-Ansatz verstehe ich zwar, ich frage mich aber, wie lang die CPU damit beschäftigt ist, Funktionen zur Prüfung von einzelnen Buchstaben aufzurufen. Wie oft rufst du token.reserve(32) auf? Kann man das nicht zentralisieren? Ist das das zentrale Token oder nicht? Man erzählt sich immer, dass Kontextwechsel zwischen Userspace und Kernel-Space teuer sind, aber unnötige Wechsel zwischen Funktionen, in denen auch immer wieder Prolog und Epilog teuer sind, ist auch blöd.

    Byte-weises Lesen und Schreiben ist echt langsam. Lesen noch schlimmer, weil Linux kein memmem mit Boyer-Moore-Algorithmus unterstützt. Mit reserve reduzierst du halt den Bloat des Allokators, aber zumindest das zeichenweise Schreiben in den Token Buffer könnte man vektorisieren ( memcpy ist zumindest auf Linux rasend schnell, ich habe einige Zeit versucht, es zu schlagen, und nur mit einem Assembler-Hack, den mir hustbaer gezeigt hat, auf Windows gesiegt.

    Ich kann dir ein memmem geben. Das ist zwar derzeit ein bisschen kaputt, weil ich keine gecachte Jumptable, die zur Needle gehört, angeben kann, aber eigentlich ist das trivial. Der Grund, warum ich das noch nicht getan habe, ist weil ich noch am nachdenken bin, wie ich diese Tabellen am schönsten statisch generieren lasse.

    tntnet schrieb:

    Dieses Vorgeben von Speicher halte ich nicht für die richtige Lösung. In aller Regel benötige ich die Daten, die vom Server kommen eben nicht vollständig aufeinanderfolgend im Speicher. Idealerweise schreibe ich einen stateful Parser, welcher Byte für Byte vom Server liest und darauf durch Zustandsübergänge reagiert. Dadurch brauche ich zu keinem Zeitpunkt den vollständigen Request im Speicher zu halten.

    Was?

    Du ließt vom Server(-socket), und dann bist du der Client, und liest einen Response. Einen Request zu lesen tut man (in der Regel), wenn man selbst der Server ist, und dann muss man nicht von einem selbst lesen.

    Bei Responses machst du das aber nicht, oder? Weil die Dinger wesentlich größer werden können.

    Hm. Mag ich auch nicht besonders. Mir ist es recht, wenn die Bibliothek nur irgendwas vom Socket liest, was nach HTTP aussieht. Es sei denn natürlich, der Nutzer merkt explizit an, dass er nur Requests oder nur Responses empfangen will, dann kann er schon, nachdem die Statuszeile durchkommt, einen EPROTO zurückgeben. Und deswegen habe ich die Codebasen für Requests und Responses auch zusammengelegt.

    Wobei dein Ansatz natürlich cache-lokaler ist als meiner, das will ich dir lassen.

    tntnet schrieb:

    Im Falle von cxxtools bedeutet das je nach http reply, dass die nächsten Daten entweder direkt vom Socket gelesen werden oder dass noch ein chunkedreader (src/http/chunkedreader.cpp) noch dazwischen ist, der eben genau so arbeitet.

    Erkläre mir mal, wie ChunkedReader::onData zero-copy ist. Für mich ist das nicht direkt ersichtlich:

    www.cplusplus.com schrieb:

    Retrieves characters from the controlled input sequence and stores them in the array pointed by s, until either n characters have been extracted or the end of the sequence is reached.

    tntnet schrieb:

    Ich habe jetzt verstanden, dass Du (Dachschaden, keine Beleidigung 😃 ) getaddrinfo für unglücklich hälst.

    Hältst.

    tntnet schrieb:

    Ja im prinzip ist immer das Problem, dass es kein asyncrones Interface to getaddrinfo gibt. Ich glaube, dass an dieser Stelle cachelokalität gar nicht so ins Gewicht fällt, da hier andere Dinge deutlich teuerer sind.

    Wieso? Der Sinn und Zweck von Caches sind, dass man Kopien in Speicher hält, der schneller zugreifbar ist. Der normale DNS-Cache des OS (oder deines Nameservers oder whatever) ist schneller als ein Roundtrip zum nächsten DNS-Server, aber immer noch langsamer, als bereits aufgelöste DNS-Daten in einer sauberen Tabelle zu haben. Du weißt nicht, was da noch für ein Rattenschwanz am DNS-Cache hängt. Diese Unsicherheit hätte ich gerne auch noch eliminiert.

    tntnet schrieb:

    Im Falle von cxxtools gibt es eine Trennung zwischen client und request. Idealerweise habe ich ein Client-Objekt, welches ich länger halte. Dadurch wird der Verbindungsaufbau inklusive Namensauflösung nur ein mal gemacht. Die Verbindung wird dann für mehrere Request wieder verwendet.

    Bei mir wird es auch aufgeteilt - wobei der Nutzer sich jetzt nicht mit der Wiederverwendung von Sockets und dergleichen rumschlagen muss.

    tntnet schrieb:

    Du hast auch noch erwähnt, dass chunked encoding schlecht ist, weil man dadurch kein sendfile verwenden kann. Das schöne ist, dass der Server entscheiden kann, was für den Anwendungsfall geeignet ist.

    Ich meinte das jetzt mehr auf den Client bezogen. Hat sich für mich so angehört, als ob der OP für seine Implementierung nur chunked-transfer unterstützen will, weil Content-Length nicht vertrauenswürdig ist.

    tntnet schrieb:

    cxxtools wirft im Falle von Fehlern exceptions. Ich könnte jetzt noch darüber schreiben, wie praktisch Exceptions sind und wie elegant man damit robuste Programme schreiben kann, aber darüber wurde schon so viel geschrieben.

    Das Gleiche könnte ich über Forward-Goto schreiben, mit dem Unterschied, dass ich nicht den Heap ansprechen muss, um mir ein Fehlerobjekt zu erstellen. Aber egal.



  • Blockade schrieb:

    Du gehst halt davon aus, dass der Server verdammt ehrlich mit dir ist, und dass du seinen Headern traust.

    Ich gehe lediglich davon aus, dass der Server HTTP spricht. Und da muss der Content length header stimmen. Ich habe Eingangs die 3 Varianten erläutert, wie man bei HTTP das Ende erkennt. Content length ist eine der 3 Varianten. Und sehr gebräuchlich. Es kann nicht sein, dass die Größe des Bodies mehr oder weniger Bytes enthält, da genau das der Indikator ist, dass der Response vollständig ist. Mehr Bytes kann schon gar nicht sein, da ich nur exakt diese Anzahl lese und bei weniger ist der Response halt noch nicht an Ende. Wie willst Du Dich auf Deinen Code verlassen? Wie soll er erkennen, dass die Antwort fertig ist?



  • tntnet schrieb:

    Mehr Bytes kann schon gar nicht sein, da ich nur exakt diese Anzahl lese und bei weniger ist der Response halt noch nicht an Ende.

    Warum eigentlich?



  • Wie soll er erkennen, dass die Antwort fertig ist?

    Bei blocking Sockets mach ich das mit Timeouts + Connection: close. Also entweder überprüfen, dass der Server seit geraumer Zeit nicht mehr antwortet, oder überprüfen, ob der Socket geschlossen wurde.

    dachschaden, wie machst du Syntaxprüfung für den Response-Body? Der Server kann dir doch jedes erdenkliche Dateiformat zurückgeben. Im Content-Type-Header kann ja auch nur Müll stehen?



  • Blockade schrieb:

    dachschaden, wie machst du Syntaxprüfung für den Response-Body? Der Server kann dir doch jedes erdenkliche Dateiformat zurückgeben. Im Content-Type-Header kann ja auch nur Müll stehen?

    Ich verwende nicht den Stateful-Ansatz von tntnet, sondern packe halt alles in einen Buffer und schreibe dann Zwischenstationen in ein Stateobjekt, damit ich z.B. nicht immer das Layout neu holen muss.

    Erste Station: Status Line End holen (erstes "\r" oder "\n" oder "\r\n").
    Zweite Station: Header Section End holen (erstes "\r\r" oder oder "\n\n" oder "\r\n\r\n").
    Dann kurz in der Header-Sektion schauen, ob wir "Transer-Encoding: chunked" haben, oder ob wir "Content-Length" haben. In beiden Fällen fängt man beim Ende der Header-Sektion (dem Beginn der Content-Sektion) an zu zählen. Habe ich weniger Bytes, sage ich der Lesefunktion, sie soll mal weitermachen. Habe ich wenigstens genug Bytes (sprich, ich habe sogar mehr als erwartet - wegen Pipelining), dann gebe ich ein A-OK zurück, und die Leseschleife bricht ohne Rollback ab.

    Merke: dieser Parsercode wird einmal aufgerufen, wenn ein HTTP-Objekt geholt werden soll (wegen Pipelining; auf diese Weise kann ich bereits prüfen, ob mir noch Objekte in den Buffer geschrieben wurden, ohne auch nur einmal select oder read/recv aufrufen zu müssen, denn diese können in den Timeout laufen - denn ich habe die HTTP-Daten von der Gegenseite ja schon) und wird auch nur dann wieder ausgeführt, wenn die Parsing-Funktion sagt, dass die Daten bisher schön aussehen, aber dass da noch was fehlt. Wenn sie die Daten nicht versteht, wird an die Lesefunktion zurückgegeben, dass sie aufhören soll und dass wir halt verloren haben (was dann mit einem Rollback von Buffern verbunden ist, aus denen sich der Nutzer aber immer noch die Daten aus einem Positionsobjekt rauspoppeln kann).

    Danach lass ich dann ein Objekt für den einfachen Zugriff auf diese Daten zeigen (keine Kopie, das Ding zeigt direkt auf die Daten im Buffer).

    In Header-Feldern kann Müll drinstehen, das ist wahr. Was sind deine Schutzmöglichkeiten?

    1. Timeout.
    Wenn nicht schnell genug Daten vorliegen, kannst du zumachen und die Ressourcen für was besseres nutzen. Kann ja sein, dass jemand gerade einen DoS versucht.
    2. Bufferlimit.
    Jemand gibt dir eine Content-Length von 12345678901234567890123456789? Kannst du den Socket direkt dichtmachen. Je nachdem, welches Limit du für die Verbindung fahren willst.

    Damit fängst du zu wenig und zu viele Daten ab. Gut, wenn ich einen echten DoS fahren würde, dann würde ich dir erst alle 5 Sekunden oder so ein Byte zusenden, bis du die Content-Length hast. Oder halt nur Chunked-Transfer mit einem 1, bevor der Timeout wieder abläuft. Du könntest ja einstellen, dass du pro Kommunikationsobjekt nur einen Timeout von 5 Sekunden maximal einstellst, anstatt dass der Timeout bei jedem erfolgreichen read/recv erneuert wird. Und bestimmt möchtest du auch prüfen, ob der Kamerad Zinnsoldat, mit dem du verbunden bist, nicht schon 900 andere Verbindungen aufhat oder so. Aber das sind relativ leichte Tuning-Sachen, das hat so direkt erstmal nichts mit HTTP zu tun.



  • dachschaden schrieb:

    Wenn nicht schnell genug Daten vorliegen, kannst du zumachen und die Ressourcen für was besseres nutzen. Kann ja sein, dass jemand gerade einen DoS versucht.

    Wie kann man denn da DoS machen? Was genau macht man damit kaputt, außer einen weiteren offenen Deskriptor zu haben?



  • Blockade schrieb:

    Wie kann man denn da DoS machen? Was genau macht man damit kaputt, außer einen weiteren offenen Deskriptor zu haben?

    Wenn du einen Server aufmachst, machst du in der Regel einen listen -Aufruf. Dem übergibst du ein Backlog, also wie viele eingehende Verbindungen du so haben willst. Wenn ich dich DoSen wollte, würde ich also so viele Verbindungen aufmachen, wie ich wollte, damit die anderen keine Slots bekommen.



  • dachschaden schrieb:

    Offtopic-Bullshit, mein zweiter Post ist wieder on-topic:

    camper schrieb:

    Warum schlägst du es nicht mal nach und lenkst nicht durch Anderes ab?

    In deinem Fall würde dann die "Beleidigung" umschlagen in eine Situation, in der sich die "Linken" (sowohl Deutschland als auch die U.S.A.) über einzelne Wörter echauffieren. "Did you just assume my gender?" hört sich erst mal wie ein netter Scherz an, bis man sich vergegenwärtigt, dass es Leute gibt, die bereits dadurch beleidigt sind, dass man ihr physikalisches Geschlecht benannt hat.

    Und für so 'ne Kinderkacke habe ich wieder Zeit noch Bock. Wenn mir jemand sagt, da und da stinkt mein Code, dann danke ich ihm - wenn die Vorwürfe stimmen. Wenn mir jemand sagt, ich stinke aus dem Mund, dann entschuldige ich mich und versuche, den Geruch zu entfernen/übertünchen. Vielleicht mag es bei dir angebracht sein, den Boten zu erschießen - aber ich mache das nur dann, wenn der Bote Unsinn erzählt.

    Und hier lügst du ja auch nur wieder und lenkst ab.
    1. Offensichtlich nimmst du dir ja doch die Zeit und musst unbedingt das letzte Wort haben. Da ist jede Menge Bock da. Im anderen Thread hast du ja auch groß angekündigt, nicht mehr mitspielen zu wollen, und dann kamen doch noch mehrere Antworten. Kindergarten? Ja, da stimme ich zu.
    2. Ich sehe nicht einmal im Ansatz was der erste Absatz überhaupt bezwecken soll oder mit dem Thema zu tun hat. Du behauptest nur etwas ohne auch nur im Ansatz zu skizzieren, wie dies logisch mit der Diskussion zusammenhängen soll.

    dachschaden schrieb:

    camper schrieb:

    Das Erste, was auffallen muss, ist, dass es auf den Wahrheitsgehalt der Aussage nicht ankommt. Das Wie, Warum und Wann (Kontext!) kann erheblich wichtiger sein.

    Viele Menschen ordnen das so ein, ja.

    Viele Menschen leben auch in einer Blase, in der Sachverhalte schön konsistent bleiben. Und wenn neue Sachverhalte reinkommen, die die alten invalidieren, dann wird zurückgefeuert. Backfire-Effekt, halt.

    Mit sowas halte ich mich nicht auf, sorry. Wenn du dadurch beleidigt wirst, dass ich deinem Code ein negatives, aber objektiv nachvollziehbares Attribut zuweise, welches nicht nur darauf abzielt, die Person anzugreifen ("Was für ein undurchsichtiger Scheißcode"), dann solltest du künftig keinen Code mehr veröffentlichen. Das ist das Beste für uns und für dein Ego.

    Ja, aufhalten tust du dich mit anderen Dingen. Etwa damit, Leuten deutlich zu machen, für wie bescheuert du sie hälst. Meinen Code jedenfalls hast du nicht kritisert - denn um so etwas ging es ja gar nicht. Wiederum postet du nur ein hypothetisches Szenario ohne Relevanz zu dem was faktisch vorfällt.

    dachschaden schrieb:

    camper schrieb:

    Das Beleidigung kann sich auch aus dem, was nicht gesagt aber impliziert wird, ergeben. Auch muss die Beleidigung nicht unbedingt in der Absicht des Senders liegen, sondern kann auf einem Missverständnis beruhen.

    Deswegen gibt es das Konzept der Nachfrage.

    Wahr. Und irrelevant: der Text war gut genug strukturiert um zu erkennen, dass ich zunächst einmal nur die zitierte Wikipediadefinition analysiert habe. Die Subsumtion folgt ja erst im nächsten Absatz.

    dachschaden schrieb:

    camper schrieb:

    Es kann eine Beleidigung sein. Insbesondere (aber nicht ausschlieslich, s.o.) dann, wenn diese Behauptung nicht durch durch entsprechende Beobachtungen gedeckt sind.

    OK, dann denk' dir mal folgenden Sachverhalt:

    - ich sage "X".
    - du sagst, ich hätte "XYZ" gesagt.
    - ich sage, du halluzinierst.

    Jetzt kann es natürlich sein, dass ich nur halluziniert hätte, dass du "XYZ" gesagt hast - aber wenn das so ist, warum hast du dann bisher kein konkretes Beispiel benannt? In diesem Thread oder in dem anderen? Stattdessen geht es hier um Meinungen. Meinungen kann man in der "Jenseits der Programmierung"-Sektion loswerden. Gib mir harte Fakten.

    Hypothetische Szenarien; wie du selbst verlangst, soll ich mir das nur denken, es ist also nicht das, was vorgefallen ist und tatsächlich zur Diskussion steht, nähmlich:
    - du sagst "X"
    - ich antworte erstmals im Thread und erkläre was es bedeutet, wenn du "X" sagst
    - du sagst, ich halluziniere.
    Eben weil ein Werturteil als solches kein wahrnehmbarer Fakt ist (nur die Tatsache, dass es getätigt wurde, ist eines), ist hier keine logische Verbindung zu deiner Erwiderung erkennbar. Mithin - weil ich ja nicht überzeugt bin, dass dir an kognitiven Fähigkeiten mangelt - kann ich nur unterstellen, dass du provozieren und beleidigen willst. Die harten Fakten sind das, was zuvor gepostet wurde. Grundregel in einem Diskurs kann nur sein, das derjenige, der eine Behauptung aufstellt, hierfür auch die Belege zu liefern hat. Das hast du beim Thema "du hallzunierst" bisher nicht ein einziges mal getan. Warum bloß? Um abzulenken gehst du dann gleich noch einen Schritt weiter und analysierest, warum jemand halluzunierte (Link zu Kognitiver Dissonaz etc.). Das ist eine ganz typische Strategie, Diskurs zu vermeiden und nicht zu versuchen, Konsens zu erreichen, sondern bloß recht zu haben. Es offensichtlich auch ein ad hominem Angriff. Warum? Weil es impliziert, dass es solcher Belege wegen Offensichtlichkeit nicht bedarf, und der andere Teilnehmer nur zu blöde ist, das zu erkennen. Er wird also nicht als gleichwertiger Diskussionspartner angesehen. Das ist dann auch eine Form der Herabwürdigung.

    dachschaden schrieb:

    Juristisch ist nämlich Beleidigung definiert:

    Die Beleidigung trotz Wahrheitsbeweis: Eine solche liegt vor, wenn trotz einer Kundgabe wahrer Tatsachen gegenüber Dritten den Betroffenen gewissermaßen "an den Pranger stellen" würde, d.h. bei der Behauptung inhaltlich ein besonders herabwürdigender Tonfall oder eine besonders gehässige Einkleidung feststellbar wäre.

    Iss klar...
    Den Beweis hast du nie erbracht, die Erweislichkeit wird von der anderen Seite bestritten. Klar, dass du natürlich trotzdem nur auf den Fall betrachten musst, dass du recht hättest... also wieder hypothetisches Szenario und ausserdem Thema verfehlt: schliesslich habe ich mich auch ausdrücklich nicht auf eine juristische Definition bezogen. Die ist nähmlich in Hinblick auf Verhaltensnormen im Forum nicht besonders nützlich: wäre die juristische Dimension alles, was zu beachten ist, bräuchten wir so etwas wie Etiquette nicht. Die hätte dann bloß deklatorische Bedeutung und sanktionierte, was sowieso schon - von Gesetzes wegen - verboten ist.

    Deine Argumentation läuft darauf hinaus zu behaupten, dass weil dein Verhalten nicht strafwürdig (i.S.d. Strafrechts) ist - einer Ansicht, der ich ohne Weiteres zustimme - sie auch nicht kritikwürdig sein kann.

    Ich bebsichtige nicht, durch Masse zu beeindrucken. Auf den Rest antworte ich nicht, weil die Argumenation nach dem gleichen - fehlerhaften - Schema erfolgt (ich habe mir auch nicht die Mühe gemacht, bis ganz zum Ende zu lesen: das wäre eine Quälerei wegen mangelnder Relevanz und innerer Konsistenz). Wie ich schrieb, funktioniert meine Argmentation im Wesentlichen auch unter Zugrundelegung eine juristischen Beleidigungsbegriffes; damit sollte deutlich sein, dass ich gleichzeitig meine, dass sie ohne Umformulierung nicht Wort für Wort darunter subsumiert werden kann. Klar dass du natürlich kleinlich trotzdem jeden Satz einzeln genau unter diesem Gesichtspunkt auseinandernehmen must... und dann kommen auch gleich wieder die Wenn-Szenarien ohne jede gezeigte Relevanz. Offensichtlich soll hier nur durch viel Text erschlagen werden.



  • dachschaden schrieb:

    Dein Stil macht bei mir irgendwie den Eindruck, als ob du mit der Grammatik haderst - hier mal ein Beispiel:

    void HeaderParser::state_qparam(char ch)
    {
        if (ch == ' ' || ch == '\t')
        {
            log_debug("queryString=" << token);
            ev.onUrlParam(token);
            token.clear();
            token.reserve(32);
            state = &HeaderParser::state_protocol0;
            return;
        }
        else
        {
            token += ch;
            return;
        }
    }
    

    Warum machst du da nicht direkt:

    void HeaderParser::state_qparam(char ch)
    {
        if (ch != ' ' && ch != '\t')
        {
            token += ch;
            return;
        }
    
        log_debug("queryString=" << token);
        ev.onUrlParam(token);
        token.clear();
        token.reserve(32);
        state = &HeaderParser::state_protocol0;
    }
    

    Nur mal aus Neugier: Was ist daran so schlimm? IF..ELSE ist doch korrektes C++. Die beiden "return" könnten hier allerdings entfallen. Da die Funktion nach dem ELSE sofort endet würde auch das gehen:

    void HeaderParser::state_qparam(char ch)
    {
        if (ch == ' ' || ch == '\t')
        {
            log_debug("queryString=" << token);
            ev.onUrlParam(token);
            token.clear();
            token.reserve(32);
            state = &HeaderParser::state_protocol0;
            return;
        }
    
        token += ch;
    }
    

    Ich finde ja das sich "Wenn A oder B" leichter lesen lässt als "Wenn nicht A und nicht B".



  • temi schrieb:

    Nur mal aus Neugier: Was ist daran so schlimm? IF..ELSE ist doch korrektes C++. Die beiden "return" könnten hier allerdings entfallen. Da die Funktion nach dem ELSE sofort endet würde auch das gehen

    Kritischer Pfad und so. Deine Funktion hat eine Aufgabe; der Hauptpfad sollte nicht irgendwo abzweigen, sondern bis zum Ende durchgebracht werden.

    Korrekt ist das natürlich. Aber auf mich macht das immer den Eindruck, dass die Person nicht über den Code nachgedacht hat. Ich war mal bei einer Firma, in der der Chefprogrammierer den kritischen Pfad in 5 oder 6 if-Scopes hatte (EDIT: über 1000 Zeilen). Was das für die Lesbarkeit bedeutete, muss ich dir hoffentlich nicht erklären.

    temi schrieb:

    Ich finde ja das sich "Wenn A oder B" leichter lesen lässt als "Wenn nicht A und nicht B".

    Finde ich nicht. "Wenn nicht A und nicht B, dann raus. Ansonsten weitermachen." Wobei man sich das "ansonsten" direkt sparen kann, weil ja schon raus ist.



  • dachschaden schrieb:

    OK, dann denk' dir mal folgenden Sachverhalt:

    - ich sage "X".
    - du sagst, ich hätte "XYZ" gesagt.
    - ich sage, du halluzinierst.

    Das ist doch genau die Art und Weise, wie Du kommunizierst. Ich würde auf die "XYZ" aussage nicht mit einem Affront reagieren und meinem Kommunikationspartner angreifen, indem ich sage, dass er halluziniert. Eher würde ich ihn freundlich und respektvoll darauf aufmerksam machen, dass er mich offensichtlich falsch verstanden hat und versuchen, meine Aussage zu präzisieren. Da werfe ich ihm nichts vor, sondern halte es durchaus für möglich, dass ich mich unklar ausgedrückt habe. Die Reaktion "du halluzinierst" ist ein Vorwurf.

    Suche mal nach ich und du Botschaften. Darüber ist viel geschrieben worden.

    Und jetzt nochwas zum Thema:

    dachschaden schrieb:

    Wenn du einen Server aufmachst, machst du in der Regel einen listen -Aufruf. Dem übergibst du ein Backlog, also wie viele eingehende Verbindungen du so haben willst. Wenn ich dich DoSen wollte, würde ich also so viele Verbindungen aufmachen, wie ich wollte, damit die anderen keine Slots bekommen.

    Der Backlog Parameter sagt nicht aus, wie viele Verbindungen der Socket aufnehmen kann. Er sagt lediglich aus, wie viele Verbindungsanfragen gesammelt werden, die noch nicht mit accept angenommen wurden. Schreibe ich einen Server, werde ich jede Verbindung unmittelbar mit accept annehmen und damit den Backlog abbauen.

    Du machst auf mich den Eindruck, als wüsstest Du alles. Aber in dem Fall glaube ich, dass Du was falsch verstanden hast. Oder ich habe mal wieder Deine Erläuterung missinterpretiert oder eventuell sogar halluziniert?

    Ach ja - und dieses if-else geraffel in meinem Code könnte ich tatsächlich klarer schreiben. Du hast Recht. Normalerweise achte ich sehr darauf, aber an der Stelle war ich offensichtlich ein wenig nachlässig. Ich ändere das gleich mal.



  • Jetzt habe ich mir die Stelle im Code noch mal genauer angeschaut. Isoliert betrachtet sollte man das return weg lassen. Aber im größeren Kontext lasse ich es lieber drin. Es ist so klarer.

    Im nächsten State sieht man es:

    void HeaderParser::state_protocol0(char ch)
        {
            if (ch == ' ' || ch == '\t')
            {
                return;
            }
            else if (std::isalpha(ch))
            {
                token.reserve(32);
                token = ch;
                state = &HeaderParser::state_protocol;
                return;
            }
            else
            {
                log_warn("invalid character " << chartoprint(ch) << " in http protocol field");
                state = &HeaderParser::state_error;
                return;
            }
        }
    

    Hier könnten die returns auch weg gelassen werden. Allerdings gleich im ersten if-Block steht ein einsames return. Logisch könnte ich es weg lassen, aber dann ist nicht auf dem ersten Blick klar, dass hier bei einem space oder tab nichts gemacht werden soll. Whitespace soll an der Stelle einfach übersprungen werden, führt also zu keinem anderen Zustand.

    Daher halte ich es für sinnvoll, die returns konsistent im gesamten Parser genau so zu setzen. Leider habe ich mich aber selbst nicht daran gehalten, sondern in anderen Zuständen dann doch aufs return verzichtet. Konsistent ist das nicht. Ich denke, in dem Fall ist das aber entschuldbar, da jeder Zustand für sich sehr übersichtlich ist. Also ich verzeihe mir zumindest mal 😃 .

    Das ist übrigens auch eine schöne Stelle, wo Daten vom Socket gelesen werden und gleich verworfen werden, da sie nicht relevant sind. Dafür brauche ich keinen Platz im Puffer. Auch andere Zeichen führen nur zu Zustandsübergängen und werden nicht zwischengespeichert.

    Ein solcher zustandsbasierter Parser macht das parsen von komplexen Zusammenhängen relativ überschaubar.

    Sicher könnte man bemängelt (und das tut Dachschaden ja auch), dass für jedes Zeichen ein Funktionsaufruf erfolgt. Ich habe andere Parser, wo das ganze in einem großen switch-case Ausdruck statt findet (z.B. src/uri.cpp). Das mit dem Aufruf haben wir mal ausprobiert. Bei Benchmarks haben wir keinen Performanceunterschied ausmachen können.


Anmelden zum Antworten