Schnidelwutz: Content-Length Header senden, Telnet

Hallo,

manchmal nutze ich zu Testzwecken Telnet oder besser noch Curl. Wenn man Post-Daten sendet, erwarten manche Server -je nach Konfiguration-, dass das Requestheader-Field "content-length" gesetzt ist, und zwar mit dem richtigen Wert.

Welche Tools nutzt ihr, um diesen Wert zu erhalten, z.b. von einem Textfile? Einfach Dateigröße angucken vermutlich bei Dateien. Wie sieht es mit Daten aus, die nicht in einer Datei vorliegen, wie z.b. dieser Text hier. Würdet ihr den in eine Datei kopieren, um dann die Dateigröße zu erhalten? Und dabei natürlich auf die richtige Kodierung achten...

Auf Antworten freut sich
Schnidelwutz

  1. Hallo,

    manchmal nutze ich zu Testzwecken Telnet oder besser noch Curl.

    Noch besser: Perl, LWP::UserAgent (s.Anm. 1)

    Wenn man Post-Daten sendet, erwarten manche Server -je nach Konfiguration-, dass das Requestheader-Field "content-length" gesetzt ist, und zwar mit dem richtigen Wert.

    Das erwartet bei einem POST jeder Server (HTTP).

    Welche Tools nutzt ihr, um diesen Wert zu erhalten, z.b. von einem Textfile? Einfach Dateigröße angucken vermutlich bei Dateien.

    Der Request-Header Content-Length hat als Wert (zu haben): Die exakte Länge des gesamten Message-Body. Sofern der gesamte Message-Body nur die Datei selbst ist, wäre "Content-Length" => -s File

    1. ermittelt den exakten Wert für Content-Length selbst

    Hotti

    1. Hi!

      Wenn man Post-Daten sendet, erwarten manche Server -je nach Konfiguration-, dass das Requestheader-Field "content-length" gesetzt ist, und zwar mit dem richtigen Wert.
      Das erwartet bei einem POST jeder Server (HTTP).

      Nein, das betrifft nicht jeden Server. Content-Length ist ein SHOULD-Wert, kein MUST-Wert. Also darf ein Server sich eigentlich nicht beklagen, wenn keiner kommt. Der Apache macht es nicht und der IIS auch nicht. Wenn das ein Server macht, dann ist das aufgrund der Verbreitungsdaten also die Ausnahme. Mir ist auch schon eine Implementation begegnet, die unbedingt einen User-Agent-Header haben wollte. Auch das ist ist nicht die Regel sondern die Ausnahme.

      Lo!

    2. Moin!

      Welche Tools nutzt ihr, um diesen Wert zu erhalten, z.b. von einem Textfile? Einfach Dateigröße angucken vermutlich bei Dateien.

      ~ echo "Das ist ein Text" | wc -c

      echo "Das ist ein Töxt" | wc -c  # Vergleiche in einer Shell mit UTF-8 als Zeichensatz ...

      wc -c textdatei

      wc -c < textdatei # unterbindet, dass etwas wie "13546 textdatei" zurück gegeben wird.

      man 1 wc oder ~ info wc liefert weitere Hilfe

      MFFG (Mit freundlich- friedfertigem Grinsen)

      fastix

      1. Moin!

        Welche Tools nutzt ihr, um diesen Wert zu erhalten, z.b. von einem Textfile? Einfach Dateigröße angucken vermutlich bei Dateien.

        ~ echo "Das ist ein Text" | wc -c

        echo "Das ist ein Töxt" | wc -c  # Vergleiche in einer Shell mit UTF-8 als Zeichensatz ...

        wc -c textdatei

        wc -c < textdatei # unterbindet, dass etwas wie "13546 textdatei" zurück gegeben wird.

        man 1 wc oder ~ info wc liefert weitere Hilfe

        danke Fastix, das ist gut!

      2. hi fastix;

        ~ echo "Das ist ein Töxt" | wc -c  # Vergleiche in einer Shell mit UTF-8 als Zeichensatz ...

        Danke Dir, schönes Stichwort: uff acht ;)

        Content-Lenght will die Anzahl der Bytes. Nicht die Anzahl der Zeichen. Also Acht gebe ;)

        Und nochwas für die Bastler unter uns: Bei einem POST wird serverseitig aus STDIN gelesen, das ist ein Handle, der Bytes erwartet und nicht etwa tagged characterstrings. Es gibt zwei Möglichkeiten, aus einem Handle zu lesen

        1. mit bekannter Längenangabe <= Content-Length
        2. solange bis keine Daten mehr kommen.

        Ich bevorzuge 1)

        Hotti

        1. Hi!

          Und nochwas für die Bastler unter uns: Bei einem POST wird serverseitig aus STDIN gelesen, das ist ein Handle, der Bytes erwartet und nicht etwa tagged characterstrings.

          Bei einem Request liest erst einmal der Webserver. Wie der das an andere Anwendungen weiterreicht ist systemabhängig ung nicht so allgemeingültig, wie du das geschrieben hast. Zudem ist eine Datenquelle wie STDIN eine Einbahnstraße. Sie liefert Daten und erwartet keine.

          Es gibt zwei Möglichkeiten, aus einem Handle zu lesen

          1. mit bekannter Längenangabe <= Content-Length
          2. solange bis keine Daten mehr kommen.
            Ich bevorzuge 1)

          Mit welcher Begründung? Was ist, wenn die Längenangabe nicht richtig ist? Der programmiertechnische Aufwand ist für beide Fällen ziemlich gleich: Schleife mit Abbruchbedingung - die eine prüft auf eine Länge, die andere auf EOF. Variante 1) hat jedoch gegenüber 2) die beiden Nachteile, dass bei zu kleiner Angabe zu wenig Daten gelesen werden und bei zu großer Angabe Leseversuche über das Ende hinaus stattfinden. Um das zu verhindern muss man bei 1) also ebenfalls auf die Abbruchbedingung von 2) testen. Und dann kann man mit etwas weniger Aufwand gleich 2) nehmen.

          Lo!

          1. hi d,

            Es gibt zwei Möglichkeiten, aus einem Handle zu lesen

            1. mit bekannter Längenangabe <= Content-Length
            2. solange bis keine Daten mehr kommen.
              Ich bevorzuge 1)

            Mit welcher Begründung? Was ist, wenn die Längenangabe nicht richtig ist? Der programmiertechnische Aufwand ist für beide Fällen ziemlich gleich: Schleife mit Abbruchbedingung - die eine prüft auf eine Länge, die andere auf EOF.

            Wenn die Länge bekannt ist (1), brauchst Du keine Schleife. Es sei denn, Du willst puffern.

            Hotti

            1. Hi!

              Es gibt zwei Möglichkeiten, aus einem Handle zu lesen

              1. mit bekannter Längenangabe <= Content-Length
              2. solange bis keine Daten mehr kommen.
                Ich bevorzuge 1)
                Mit welcher Begründung? Was ist, wenn die Längenangabe nicht richtig ist? Der programmiertechnische Aufwand ist für beide Fällen ziemlich gleich: Schleife mit Abbruchbedingung - die eine prüft auf eine Länge, die andere auf EOF.
                Wenn die Länge bekannt ist (1), brauchst Du keine Schleife. Es sei denn, Du willst puffern.

              Theoretisch kann man auch gleich die Anzahl Bytes lesen, die in Content-Length angegeben ist (wenn diese Angabe stimmt). Praktischer ist es jedoch, wenn man nicht die gesamte Menge auf einmal sondern in kleinen Häppchen verarbeitet.

              Lo!

              1. hallo?

                Theoretisch kann man auch gleich die Anzahl Bytes lesen, die in Content-Length angegeben ist (wenn diese Angabe stimmt). Praktischer ist es jedoch, wenn man nicht die gesamte Menge auf einmal sondern in kleinen Häppchen verarbeitet.

                man, man ;)

                Neulich habe ich einen Type kennengelernt, der braucht jeden Tag ein Erfolgserlebnis, was darin besteht, einmal am Tag so richtig NEIN sagen zu können ;)

                Aber zur Sache:

                Das Content-Management meiner Website (siehe Link) wird komplett über HTTP abgewickelt. Da wird die komplette virtuelle Verzeichnisstruktur (boot) oder Zweige davon (branching) samt Inhalt in ufz-8 in eine binäre Datenstruktur serialisiert per HTTP/POST zum Server geschickt. Der Serverprozess erzeugt aus diesem Stream einen Hash, der komplett im Hauptspeicher vorliegen muss, damit Branches in das ORM an der richtigen Stelle eingehängt werden können; in Perl ist das eine Zeile Code. Sowas geht nicht häppcheneise. Logisch auch, dass dazu die Längenangabe des Upload-Streams in Content-Length genau stimmen muss.

                Würdest Du als Programmierer dazu mit unsicheren Längenangaben arbeiten?

                [] Nein

                --Hotti

                1. Hi!

                  Das Content-Management meiner Website (siehe Link) wird komplett über HTTP abgewickelt. Da wird die komplette virtuelle Verzeichnisstruktur (boot) oder Zweige davon (branching) samt Inhalt in ufz-8 in eine binäre Datenstruktur serialisiert per HTTP/POST zum Server geschickt. Der Serverprozess erzeugt aus diesem Stream einen Hash, der komplett im Hauptspeicher vorliegen muss, damit Branches in das ORM an der richtigen Stelle eingehängt werden können; in Perl ist das eine Zeile Code. Sowas geht nicht häppcheneise. Logisch auch, dass dazu die Längenangabe des Upload-Streams in Content-Length genau stimmen muss.

                  Du wirfst mal wieder Sachen zusammen und durcheinander. Es geht nicht um die Weiterverarbeitung sondern erst einmal nur um das Auslesen der POST-Daten. In welche Struktur du sie dann für die Weiterverarbeitung bringst, ist völlig nebensächlich für die Frage, ob man sich auf die Content-Lenght-Angabe verlassen soll und ob man sie überhaupt braucht. Die einfachste Lösung ist - egal ob der Content-Lenght-Header vom Client mitgesendet und/oder richtig ist - eine Schleife, die bis zum Datenende Häppchen liest (und diese dann in irgendeine Struktur oder auch nur aneinander in ein Byte-Array oder String oder sonstwas hängt).

                  Würdest Du als Programmierer dazu mit unsicheren Längenangaben arbeiten?
                  [x] Nein

                  Genau, und darum würde ich diese Content-Lenght-Angabe komplett ignorieren. Wenn ich einen Client schreiben müsste, sendete ich sie auch nur dann, wenn ein (Fremd-)Server ohne sie nicht mitspielt oder die Zielserver unbekannt sind (z.B. wenn sie zur Entwurfszeit nicht feststehen).

                  Lo!

                  1. Moin dedlfix,

                    Es geht nicht um die Weiterverarbeitung sondern erst einmal nur um das Auslesen der POST-Daten. In welche Struktur du sie dann für die Weiterverarbeitung bringst, ist völlig nebensächlich für die Frage, ob man sich auf die Content-Lenght-Angabe verlassen soll und ob man sie überhaupt braucht. Die einfachste Lösung ist - egal ob der Content-Lenght-Header vom Client mitgesendet und/oder richtig ist - eine Schleife, die bis zum Datenende Häppchen liest (und diese dann in irgendeine Struktur oder auch nur aneinander in ein Byte-Array oder String oder sonstwas hängt).

                    Das ist nicht so einfach. Du liest keine Datei aus, es gibt kein EOF, du befindest dich in einem Netzwerk-Kontext. Woran erkennst du das "Datenende?" Wenn du liest, bis nichts mehr kommt, wirst du entweder bis zum Timeout blockieren oder du wirst nicht alle Daten lesen.

                    Deshalb gibt es bei HTTP halt entweder den Content-Length-Header oder ein Transfer-Encoding wie chunked. Bei Content-Length ist klar, wieviel gelesen werden muss, da es durch den Client bekannt gegeben wird. Bei Transfer-Encoding: chunked werden die Daten häppchenweise übertragen, und es wird jedesmal die Länge des Datums mitgegeben:

                    HTTP/1.1 200 OK
                    Content-Type: text/plain
                    Transfer-Encoding: chunked

                    25
                    This is the data in the first chunk

                    1C
                    and this is the second one

                    3
                    con
                    8
                    sequence
                    0

                    Die HTTP-RFC sagt dazu:

                    [...] The presence of a message-body in a request is signaled by the
                       inclusion of a Content-Length or Transfer-Encoding header field in
                       the request's message-headers. [...]

                    Absichern gegen falsche Längen kann man sich relativ einfach: für eine zu große Angabe gibt es einen Receive-Timeout. Und für eine zu kurze Angabe, ja mei, dann ist halt der nächste Request syntaktisch falsch.

                    LG,
                     CK

                    1. Hi!

                      Es geht nicht um die Weiterverarbeitung sondern erst einmal nur um das Auslesen der POST-Daten. In welche Struktur du sie dann für die Weiterverarbeitung bringst, ist völlig nebensächlich für die Frage, ob man sich auf die Content-Length-Angabe verlassen soll und ob man sie überhaupt braucht. Die einfachste Lösung ist - egal ob der Content-Length-Header vom Client mitgesendet und/oder richtig ist - eine Schleife, die bis zum Datenende Häppchen liest (und diese dann in irgendeine Struktur oder auch nur aneinander in ein Byte-Array oder String oder sonstwas hängt).
                      Das ist nicht so einfach. Du liest keine Datei aus, es gibt kein EOF, du befindest dich in einem Netzwerk-Kontext. Woran erkennst du das "Datenende?" Wenn du liest, bis nichts mehr kommt, wirst du entweder bis zum Timeout blockieren oder du wirst nicht alle Daten lesen.

                      Ein Verbindungsende hätte ich hier als "Dateiende" angenommen ... Aber das gibts ja zu dem Zeitpunkt nicht, weil die Connection offen bleibt, um die Response darüber zu senden. Nichtsdestotrotz kann man mit PHP von php://input einfach bis feof() lesen. feof() ergibt true, wenn die von vom Client in Content-Length angegebenen Anzahl an Bytes gelesen wurde. Insofern muss man (für PHP) immer noch nicht Content-Length selbst auswerten. (Für andere Systeme mag das anders aussehen. Abgesehen davon besteht unter PHP selten die Notwendigkeit, php://input zu befragen, denn die Daten für bekannte Mime-Types findet man in $_POST und $_FILES, für unbekannte wird $HTTP_RAW_POST_DATA gefüllt.)

                      Lo!

                      1. Moin dedlfix,

                        Insofern muss man (für PHP) immer noch nicht Content-Length selbst auswerten.

                        Das ist richtig. Ich wollte eigentlich auch nur korrigierend eingreifen. Content-Length oder Transfer-Encoding: chunked ist in einem Netzwerk-Kontext notwendig und weitestgehend zuverlässig bzw. soweit absicherbar, da HTTP keine andere Möglichkeit bietet, das Ende einer Nachricht zu erkennen.

                        LG,
                         CK

  2. Hi!

    Wie sieht es mit Daten aus, die nicht in einer Datei vorliegen, wie z.b. dieser Text hier. Würdet ihr den in eine Datei kopieren, um dann die Dateigröße zu erhalten?

    Nein, man kann auch die Länge von im Speicher gehaltenen Datenstrukturen ermitteln.

    Lo!

    1. Hallo

      Nein, man kann auch die Länge von im Speicher gehaltenen Datenstrukturen ermitteln.

      das ist schon klar. Ich fragte, was bei euch für sowas best practice wäre.

        
      POST /telnet_1.php HTTP/1.1  
      HOST: example.com  
      
      

      Wenn ich jetzt hier keinen Header "content-length" einfüge oder diesen auf 0 lasse, ist mir bei meinem Testserver schonmal gar nicht möglich, einen body einzufügen.

      Aber gut, nehmen wir an, wir erweitern um den content-lenght-header:

        
      POST /telnet_1.php HTTP/1.1  
      HOST: example.com  
      content-length: 0  
      
      

      Als Body hätte ich gerne "<xml><el>top</el></xml>". Wie genau wäre jetzt das Vorgehen, um diese Content-Length zu ermitteln?

      1. Hi,

        Als Body hätte ich gerne "<xml><el>top</el></xml>". Wie genau wäre jetzt das Vorgehen, um diese Content-Length zu ermitteln?

        Wenn du den Rest „von Hand“ (a.k.a. telnet) machen willst - dann mach diesen Schritt ebenso manuell.
        Welche Möglichkeit dazu dir aussuchst, welche dir am komfortabelsten erscheint (sofern man bei Kommunikation per telnet von Komfort reden kann) – das ist deine Entscheidung.

        Beachte je nach Vorgehen aber, dass Anzahl Zeichen nicht gleich Anzahl Bytes sein muss.

        MfG ChrisB

        --
        RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
        1. Hallo Chris B,

          Wenn du den Rest „von Hand“ (a.k.a. telnet) machen willst - dann mach diesen Schritt ebenso manuell.
          Welche Möglichkeit dazu dir aussuchst, welche dir am komfortabelsten erscheint (sofern man bei Kommunikation per telnet von Komfort reden kann) – das ist deine Entscheidung.

          Richtig, komfortabel ist Telnet natürlich nicht. Mir geht es auch eher nur darum, ob es für sowas eine "best practice" gibt, also z.b. man würde dann die Stringlänge (im Falle von Ascii) per Shell ermitteln oder die Bytelänge (im Falle einer Kodierung, die mehr als 1 Byte/Zeichen nutzt)

          Aber danke für die Antwort, es macht anscheinend jeder, wie er will. Das ist ok.

          1. Hi!

            Mir geht es auch eher nur darum, ob es für sowas eine "best practice" gibt, also z.b. man würde dann die Stringlänge (im Falle von Ascii) per Shell ermitteln oder die Bytelänge (im Falle einer Kodierung, die mehr als 1 Byte/Zeichen nutzt)

            Die Kodierung spielt keine Rolle. Im Gegenteil, du _musst_ sie unberücksichtigt lassen und die Anzahl Bytes[*] zählen. Und das über alles, denn POST-Daten (besonders die aus Formularen) werden üblicherweise auch noch URL-kodiert und als Name-Value-Pärchen übertragen. Auch diese Metadaten müssen mitgezählt werden.

            Aber ich frage mich, was der ganze Aufwand soll? Was hat denn der empfangende Server davon, dass er dass er vorher weiß, wieviel Daten kommen sollen, dass deiner darauf zu bestehen scheint? Und was für ein Nachteil ist es denn, wenn er die Länge nicht kennt oder eine falsche Länge bekommt. So eine Längenangabe ist doch nicht mal als (eine Art) Prüfsumme zu gebrauchen.

            Wie auch immer, wenn deine POST-Daten nur aus Daten ohne weitere Transport-Kodierung und ohne Metadaten gesendet werden, dann kannst du die Datenquelle nach der Länge befragen oder selbst zählen. Wenn du sie für den Transport aufbereiten musst, ist ein Selbst-Zählen(-Lassen) effizienter als erst noch eine Datei anzulegen, bei der du wieder die Besonderheiten einer Multi-User-Umgebung beachten musst.

            [*] korrekterweise Oktetts, aber solange nichts anderes vereinbart wird, ist ein Byte gleich 8 Bit.

            Lo!

            1. Hallo

              Die Kodierung spielt keine Rolle. Im Gegenteil, du _musst_ sie unberücksichtigt lassen und die Anzahl Bytes[*] zählen. Und das über alles, denn POST-Daten (besonders die aus Formularen) werden üblicherweise auch noch URL-kodiert und als Name-Value-Pärchen übertragen. Auch diese Metadaten müssen mitgezählt werden.

              Ok, genau, das wusste ich.

              Aber ich frage mich, was der ganze Aufwand soll? Was hat denn der empfangende Server davon, dass er dass er vorher weiß, wieviel Daten kommen sollen, dass deiner darauf zu bestehen scheint? Und was für ein Nachteil ist es denn, wenn er die Länge nicht kennt oder eine falsche Länge bekommt. So eine Längenangabe ist doch nicht mal als (eine Art) Prüfsumme zu gebrauchen.

              Hm, ich meinte mal gelesen zu haben, dass der Server die Anfrage dann schon von vorneherein verweigern kann, wenn er weiß, dass die Datenmenge zu groß ist. Natürlich könnte man den Server zu übertölpeln versuchen, indem man bei content-length den Wert einfach fälscht.