info@a-coding-project.de

HTTP: Anwendungsbeispiele

Im letzten Teil möchten wir Ihnen nun einige praxisnahe Einblicke in HTTP bieten und Ihnen zeigen, wie bestimmte Aufgaben- und Problemstellungen behandelt werden.

Die Nachrichtenlänge feststellen

Eines der Hauptprobleme in HTTP ist festzustellen wie lang die Nachricht sein wird. Hierfür gibt es 5 Lösungsmöglichkeiten:

  • Lösung 1 besteht darin, dass bei allen Nachrichten die keinen Nachrichtenbody erwarten lediglich auf ein <CR><LF><CR><LF> gewartet werden muss.
  • Lösung 2 besteht darin, mit Hilfe des Transfer-Encoding Headers ein Verfahren zu wählen mit dem die Nachrichtenlänge sicher festgestellt werden kann.
  • Lösung 3 besteht darin, dass der Content-Length Header angegeben wird. Hierdurch kann der Client/Server noch während des Empfangs die Länge des Nachrichtenbodys ermitteln und entsprechend die Nachricht empfangen.
  • Lösung 4 besteht darin, als Mediatyp multipart/byteranges (merteilige Nachricht) zu verwenden und mit dem Range- bzw. Content-Range Header die aktuell gesendeten Bereiche anzugeben.
  • Lösung 5 besteht darin, dass der Server die Verbinung einfach nach der Übermittlung aller Daten trennt. Dieses Verfahren ist jedoch nur in HTTP 1.0 zulässig und funktioniert nur bei Responses. Der Client kann dann einfach alle Daten der Nachricht zuordnen die er empfangen hat.

Bytebereiche

Verwendet ein Client oder Server Bytebereiche zum Senden einer mehrteiligen Nachricht, ist der Empfänger der Nachricht angewiesen diese Teile wieder entsprechend zusammen zu setzen. Hier ein Beispiel dazu:

[Request]
HEAD /grossedatei.txt HTTP/1.1
Host: www.name.de

[Response]
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 283607
Content-Type: text/plain

[Request]
GET /grossedatei.txt HTTP/1.1 
Host: www.name.de
Range: bytes=0-9

[Response]
HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Length: 10
Content-Range: bytes 0-9/283607
Content-Type: text/plain

0123456789

[Weitere Requests ...]

Chunked Encoding

Das versenden einer Nachricht in mehreren Teilen erfolgt durch die Angabe Transfer-Encoding: chunked als Header des Responses. Das Schema einer solchen Nachricht ist immer das Gleiche:

[Header]

[Chunkgröße]
[Nachrichtenteil]

[Chunkgröße]
[Nachrichtenteil]

[...]

0
[Trailer]

[Ende]

Im Header wird also als erstes Transfer-Encoding: chunked angegeben, damit der Empfänger sich auf das Verfahren einstellen kann. Der Body folgt dann in mehreren Chunks (Teilen). Jeder Chunk besteht dabei aus der Größenangabe als Hexadezimalzahl gefolgt vom Zeilenwechsel (<CR><LF>) sowie dem jeweiligen Teil des Dateiinhalts. An den Dateiinhalt schließt sich wiederum der Zeilenwechsel an.
Wurde die Datei noch nicht vollständig geschickt, wird einfach der nächste Chunk angehängt. Es folgt also wieder die Chunkgröße und der jeweilige Dateiinhalt. Das ganze wird so lange fortgeführt bis die gesamte Datei gesendet wurde. Zum Abschluss der Datei wird eine Null-Zeile (0<CR><LF>) geschickt.
Optional können dann, sofern es im Header angegeben wurde, die Trailer-Header folgen.
Beispiel:

HTTP/1.1 200 OK
Server: Apache/1.3.27
Transfer-Encoding: chunked
Content-Type: text/html; charset=iso-8859-1
Trailer: Cache-Control

ee1
[Die ersten 3809 Zeichen der Datei]

ffb
[Weitere 4091 Zeichen der Datei]

c40
[Die letzten 3136 Zeichen der Datei]

0
Cache-Control: no-cache

[Ende]

Verwendung von Cookies

Die Verwendung von Cookies ist eine Sache für sich. Sie wird nicht zuletzt durch eine Vielzahl von Cookieformaten und -beschreibungen erschwert. Allgemein gesehen sind Cookies kein offizieller Bestandteil von HTTP , sie haben sich jedoch mittlerweile als quasi-Standard eingebürgert.
Ein Cookie ist eine kleine (Text-)Datei, die beim Clienten gespeichert wird. Der Server weist den Clienten dazu mit Hilfe des Set-Cookie Headers an, einen bestimmten Cookie zu speichern. Der Client ist nun angewiesen bei jeder Anfrage auf diese URL den Cookie mit zu senden (Cookie-Header), sodass der Server wiederum damit arbeiten kann. Je nach angegebenen Pfad (path=xxx) und Domain (domain=xxx) kann der Cookie aber auch bei der Anfrage an andere URL's mitgesandt werden. Beispiel:

[Request]
GET /index.php HTTP/1.1
Host: www.a-coding-project.de

[Response]
HTTP/1.1 200 OK
Set-Cookie: name=HTMLWorld; path=/; domain=www.a-coding-project.de
...

Bei Anschließenden Requests auf https://www.example.com/forum.php und https://www.example.com/program/http_1.php wird der Cookie dann jedes mal mitgeschickt:

GET /program/http_1.php HTTP/1.1
Host: www.example.com
Cookie: name=HTMLWorld

Die Lebensdauer eines Cookies hängt dabei vom Wert expires=Datum ab, der beim Setzen des Cookies übergeben wird. Wird der Wert nicht angegeben, ist der Client angewiesen den Cookie nur während dieser Sitzung zu verwenden. Sobald der Client beispielsweise beendet wird, muss auch der Cookie wieder entfernt werden. Anders ist das, wenn ein explizites Datum angegeben wird: Dann "stirbt" der Cookie exakt zu diesem Zeitpunkt.

Authentifizierung von Clienten

Besondere Bedeutung kommt der Authentifizierung des Clienten zu. Nur wenn sich der Client als einer der berechtigten Benutzer "ausweisen" kann, bekommt er im jeweiligen Fall die Datei geschickt. Die Anfrage auf Authetifizierung kommt dabei jeweils durch den Server oder Proxy mittels dem WWW-Authenticate bzw. Proxy-Authenticate Headers. Beispiel:

[Request]
GET /geheim/index.php HTTP/1.1
Host: www.name.de

[Response]
HTTP/1.1 401 Unauthorized
...
WWW-Authenticate: Basic realm="Geheimer Bereich"

Als Verfahren kann bei HTTP 1.0 lediglich BASIC verwendet werden, welches die Daten mit Base64 umwandelt. Da dieses Verfahren jedoch sehr unsicher ist (da es jeder entschlüsseln kann), wird mit HTTP 1.1 ein zweites Verfahren eingeführt: Digest.
Das gesamte Verfahren wird im RFC 2617 beschrieben und würde an dieser Stelle zu weit führen, der Vorteil von Digest ist jedoch, dass die Passwortdaten nicht mehr völlig unverschlüsselt übertragen werden.
Will ein Server dieses Verfahren verwenden, sendet er als Wert des WWW-Authenticate Headers statt dem Wort Basic das Wort Digest gefolgt von der Bereichsbeschreibung. Die Bereichsbeschreibung kann dabei entweder ein Bereich (realm="..."), eine ganze Domain (domain="...") oder keines von beiden (nonce) sein. Zusätzlich kann Digest weitere Werte verwenden, die den Bereich näher eingrenzen oder die Verschlüsselung definieren.

Über uns

Stefan Wienströer

Wir entwickeln Webanwendungen mit viel Leidenschaft. Unser Wissen geben wir dabei gerne weiter. Mehr über a coding project

Auch interessant