HTTP/1.0, HTTP/1.1, persistent Connections, Proxy und Request-Methoden

Request-Header, Response-Header und ggf. der Message-Body sind Bestandteiler eines jeden HTTP-Request

Da es über HTTP ungezählte Artikel gibt, wird sich dieser hier mit ein paar Besonderheiten begnügen. Die erste Besonderheit ist die etwas irreführende Bezeichnung Hypertext Transfer Protocol, denn HTTP überträgt nicht nur Text sondern auch reine Binaries, also Bytesequenzen mit Bytes beliebiger Wertigkeiten von 0x0 bis 0xFF.

Version HTTP/1.0

Einfacher gehts nicht: Ein HTTP-Client, z.B. ein gewöhnlicher Browser, auch User-Agent genannt, sendet einen Request zum Webserver. Nachdem beim Webserver alles angekommen ist, sendet dieser eine Response zurück zum Client. Für den Datentransport wird ein sogenanntes Socket erstellt, darunter liegt das Protokoll TCP/IP.

Das Socket können wir uns wie eine Röhre (Pipe) vorstellen: Beim Request werden ein paar Bytes in die Pipe geschoben und als Response werden Bytes aus der Röhre herausgelesen. Für Client und Server ist diese Pipe transparent. Etwas genauer ausgedrückt, besteht jeder Request aus einem oder mehreren Request-Header und dem Message-Body, nach diesem Schema:

GET-Request ohne Message Body

GET /index.html HTTP/1.0
Host: example.com

PUT-Request mit Message Body

PUT /index.html HTTP/1.0
Host: example.com
Content-Length: 10

Hallo Welt

Die Unterschiede fallen sofort ins Auge, zunächst ist mit GET oder PUT die Request-Methode qualifiziert. Mit Request-Method GET wird i.d.R. kein Message-Body gesendet und damit gibt es auch keinen Header Content-Length.

Grundsätzlich folgt dem Request-Header eine Leerzeile und falls vorhanden, kommt danach der Message-Body. Dies erfordert dann die Längen-Angabe im Request-Header Content-Length: 10 (= Anzahl der Bytes des Message-Body).

Beispiel einer Response

HTTP/1.1 200 OK
Date: Sun, 20 Oct 2001 13:30:08 GMT
Server: Apache
Content-Language: de
Cache-Control: no-cache, must-revalidate, proxy-revalidate, no-x-cache
Expires: Thu, 28 Nov 2001 01:01:01 GMT
Set-Cookie: FRAMEWORK=c47506d360f8370806018bf92a166f70
Vary: Accept-Encoding
Connection: close
Content-Type: text/html; charset=UTF-8

<!DOCTYPE HTML>
...

Anmerkung: Der Server antwortet mit HTTP/1.1, obwohl 1.0 angefordert wurde. Wesentlich ist der Response-Header Connection: Close, das heißt, dass der Server nach dem Senden der Response die Verbindung zum Client schließt. Und das macht ein Webserver nach jedem Request-Response-Zyklus, wenn der Client entweder HTTP/1.0 angefordert oder den Header Connection: Close gesendet hat.

Persistent Connection, Keep-Alive!

Wir können mehrere Requests in einer einzigen Verbindung zum Server senden, nach folgendem Schema:

GET /index.html?x=y HTTP/1.1
Host: example.com
Connection: Keep-Alive

Der Server wird die Verbindung offenhalten, solange, bis entweder ein konfiguriertes Timeout erreicht wurde, oder bis ihn ein Request erreicht mit dem Header Connection: Close. Bis dahin bewegen sich alle Daten hinein in das Pipe in Richtung Webserver. Jeder einzelne Request zu einer persistent Connection enthält vollständige Header, ggf. verschiedene Request-Methoden und Message-Bodies.

Wenn nichts mehr gesendet wurde, kann der Client daran gehen, das Socket auszulesen, diese Response enthält alle Responses zusammengefasst in einer Response. Es kommt nun auf den Client an, wie er mit einer solchen Response umgeht. Beispielsweise wird ein Browser eine HTML-Seite per HTTP/1.1 und Connection: Keep-Alive requesten, weil außer text/html i.d.R. auch noch Grafiken und andere Inhalte gesondert anzufordern sind. Gegenüber HTTP/1.0 ergibt sich somit ein erheblicher Zeitgewinn.

Anmerkung: Wenn der Server die Verbindung offenhält, kann er währenddessen auf den Gateway nach CGI/1.1 zugreifen, verschiedene Scripts oder andere Ressourcen laden. Persistent Connection heißt jedoch nicht, dass dem Webserver nachgelagerte CGI-Scripts weiterlaufen.

Response deserialisieren

Wenn mehrere Requests in einer persistent Connection an den Server gesendet wurden, ist die Response eine Sequenz in welcher mehrere Responses aufeinanderfolgen. Ein Deserializer hat nun die Aufgabe, die einzelnen Serverantworten wieder voneinander zu trennen. Damit dies fehlerfrei möglich ist, muss ein jeder Webserver die Standards konsequent einhalten. Maßgeblich hierzu ist:

Zum Deserialisieren ergeben sich somit genau drei Fälle, die, nachdem das Ende der Header (Leerzeile) festgestellt wurde, zu untersuchen sind (Pseudocode):

if      Content-Length: 123        { lese 123 bytes }
elsif   Transfer-Encoding: chunked { lese jeden Chunk mit der für ihn angegbenen Länge }
else    { Lese einfach solange bis keine Daten mehr kommen }

Das Lesen selbst erfolg dafür direkt aus dem zwischen Client und Server bestehenden Socket.

HTTP-Request über einen Proxy-Server

GET http://rolfrost.de:80/index.html HTTP/1.0
Connection: Close
Host: www-proxy.t-online.de

So sehen die Header aus, das Beispiel erklärt sich von selbst: Gut zu sehen, wo der Proxy-Server einzutragen ist und an welcher Stelle zu notieren ist, welche Webressource angefordert werden soll.

Verschiedene Request-Methoden

Grundsätzlich können Sie sich unendlich viele Namen für Request-Methoden ausdenken und Daten sowohl im URI als angehängten QUERY_STRING als auch in Message-Body übertragen. Es ist jedoch so, dass je nach Webserver und -Konfiguration die Response nicht unbedingt Ihren Erwartungen entsprechen muss. Bei einem HEAD-Request wird ein normal konfigurierter Apache-Webserver niemals Daten im Message-Body senden, auch dann nicht, wenn der Response-Header Content-Length gesendet wird.

Mein Perl Modul HTTPRequest.pm

Hier beschrieben und zum Download bereitgestellt ist es ein zweckmäßiger Ersatz für LWP::UserAgent weil es einfacher in der Handhabe ist. Es eignet sich hervorragend zur Erstellung von HTTP-Clients unbeschränkter Aufgabenstellungen. Mein Perlmodul HTTPRequest kommt vor Allem mit Persistent Connections bestens zurecht.


Anbieter: nmq​rstx-18­@yahoo.de, die Seite verwendet funktionsbedingt einen Session-Cookie und ist Bestandteil meines nach modernen Aspekten in Perl entwickelten Frameworks.