Hosted at Sorceforge.net next up previous contents
Next: Gopher Up: Hitchhiker's Guide to the Previous: NNTP   Contents

Subsections

HTTP

Das HTTP37 ist verantwortlich für das Web, was ja schon an URLs38 (zum Beispiel http://linide.sf.net/) erkennbar ist.

Wie SMTP ([*]) ist es ein ASCII-basiertes Protokoll, das heißt man kann telnet benutzen, um im Internet zu surfen...

Versionen

Heute werden HTTP 1.0 (RFC 1945) und 1.1 (RFC 2616) benutzt.

HTTP/1.1 hat einige Verbesserungen gegenüber HTTP/1.0 erhalten, zum Beispiel Keep-Alive39und virtuelle Hosts. Beiden dieser Features ist ein eigener Abschnitt gewidmet.

Der Standard-TCP-Port für HTTP (1.0 und 1.1) ist 80.

Außerdem gibt es noch HTTP-Proxies40. Dort wird, je nach Zielhost, sowohl HTTP/1.0 als auch HTTP/1.1 verwendet. Oft benutzte Ports sind 3128, 8080 und 79; Einen Standardport gibt es nicht.

Adressen

Um HTTP zu verstehen, muss man wissen, wie Internetseiten eigentlich addressiert werden.

Da gibt es zum einen die

Wenn man nun allerdings einem normalen HTTP-Server eine URL vorsetzt, kann er damit nichts anfangen: Schließlich soll er nicht als Proxy (siehe [*]) fungieren, sonden nur seine eigenen Seiten ausliefern.

HTTP/1.0

Deswegen benutzt man bei HTTP nur den Pfad (samt dem ersten /).

Ein einfacher GET-Request ("`zeig mir den Inhalt (Quelltext) einer Seite an!"') für die URL http://linide.sf.net/ sieht dann so aus:

HTTP/1.1

Als Minimalanforderung wird bei HTTP/1.1 ein zusätzliches Header-Feld vom Client erwartet, Host:

>GET / HTTP/1.1
>Host: linide.sf.net
>

Neu dazugekommen ist also nur der Host-Header. Dieser wird von vielen Hosting-Angeboten genutzt, die ihren Kunden nur Webspace, aber keinen eigenen Server. So kann also ein Kunde eine eigene Domain haben, ohne dass ein weiterer Server benötigt wird.

Der Webserver unterscheidet sein Webangebot dann einfach anhand jenes Headerfeldes.

Zu beachten ist auch, dass die Verbindung bei HTTP/1.1 nicht nach erfolgtem Reply automatisch geschlossen wird. Dies liegt am bei HTTP/1.1 standardmäßig aktiviertem Keep-Alive (siehe dazu [*]).

HTTP-Proxies

HTTP-Proxies sind wirklich cool, wie später im Kapitel über die Automatisierung mit Hilfe von Skripten ([*]) noch näher erläutert wird.

Proxies übernehmen das Auflösen des (Ziel-)Hostnamens zu einer IP-Adresse (siehe dazu [*]) und verbinden sich dann, stellvertretend für den eigenen Computer, mit dem eigenen Computer.

Die Antwort liefert der Proxy dann an den eigenen Computer zurück.

Auch hier unterscheidet sich das praktische Vorgehen wenig von HTTP/1.0 oder HTTP/1.1, nur dass

Um zum Beispiel über die Proxy proxy.as-netz.de:808043 die Seite http://linide.sf.net/uebersicht.html abzurufen, tippt man nach Verbinden mit der Proxy ein:

>GET http://linide.sf.net/uebersicht.html HTTP/1.1
>Host: linide.sf.net
>
Die Antwort (samt Statuscodes) ist dann dieselbe wie bei normalem HTTP.

Überblick

Bis jetzt sollte also folgendes klar sein:

Typ Standard-Port(s) Adressenübergabe Host-Angabe
HTTP/1.0 80 Nur Pfad nein
HTTP/1.1 80 Nur Pfad ja
HTTP-Proxy 3128, 8080 Volle URL je nach Zielprotokoll

Referer

Aber jetzt wird es erst richtig spanned: Oft will man aus irgendwelchen vollkommen unbekannten Gründen44 eine Website abrufen. Im Browser funktioniert das absolut unproblematisch, in automatisierten Skripten jedoch nicht45.

Die Magie liegt im sogenannten Referer. Der Referer ist ein spezielles Header-Feld, was die zuletzt besuchte Website enthält.

So kann ein Hoster zum Beispiel sehen, von welchen Ländern (Top-Level-Domains), von welchen Unterseiten, usw. kommt. Und er kann so auch prüfen, ob man erst die Homepage "`angeklickt"' hat, und nicht einen direkten Link benutzt.

Man kann den Referer aber natürlich auch faken. Angenommen, wir wollen via Telnet die Seite http://www.microsoft.com/unterseite.asp abrufen, der Seitenbetreiber zwingt uns aber, zuvor auf http://www.microsoft.com/ gewesen zu sein, verwendet man

>GET /unterseite.asp HTTP/1.1
>Host: www.microsoft.com
>Referer: http://www.microsoft.com/
>
Dem Referer-Feld folgt also eine URL (auch bei Proxies).

Im Kapitel über die Automatisierung von HTTP ([*]) werden dazu noch einige Beispiele folgen.

TRACE-Request

Manchmal möchte man wissen, welche Daten ein Server nach passieren aller eventuellen Proxies tatsächlich erhält. Dazu benutzt man den nru bei HTTP/1.1 vorhandenen TRACE-Request:

>TRACE http://www.linux.org/ HTTP/1.1
>Test-Header: Test-Inhalt
>
<HTTP/1.1 200 OK
<Date: Wed, 06 Aug 2003 16:46:47 GMT
<Server: Apache/1.3.28 (Linux) mod_perl/1.28 mod_ssl/2.8.15 OpenSSL/0.9.7a
<Content-Type: message/http
<X-Cache: MISS from true
<Proxy-Connection: close
<
<TRACE / HTTP/1.1
<Cache-Control: max-age=259200
<Connection: keep-alive
<Host: www.linux.org
<Test-Header: Test-Inhalt
<Via: 1.0 true:3128 (Squid/2.4.STABLE1)
<X-Forwarded-For: 10.0.0.3
<
Im Beispiel geht der Request also über eine Proxy (Squid), der ursprüngliche Absender war 10.0.0.346.

User-Agent

Manchmal bekommt man beim Surfen auch die Meldung "`Tut uns wirklich sehr sehr leid, aber wir optimieren unsere Seiten auf den Microsoft (R)(TM)(C) Internet (R)(TM)(C) Explorer (R)(TM)(C), Sie werden jedoch Mozilla. Klicken Sie hier, um sich die aktuelle Version des IE herunterzuladen..."'. Die Antwort auf die Frage "`Woher wissen die eigentlich, welchen Browser ich benutze?"' liegt wieder in einem zusätzlichen Header-Feld, das der Browser dem Server sendet: User-Agent:

>GET / HTTP/1.1
>Host: microsoft.com
>User-Agent: Mozilla/5.0 (compatible; Konqueror/3.1; Linux)
>
<HTTP/1.1 200 OK
<Server: Microsoft IIS Bug-free(TM)
<Content-Type: text/plain
<
<Sorry, aber diese Seite...

Accept-Language

Ein Seitenbetrieber kann die vom Client mitgeschickten Header aber auch für gute Zwecke nutzen: Verlangt man zum Beispiel http://debian.org/, so bekommt man (je nach Browser und Einstellungen) automatisch die deutsche Version angezeigt. Diese Information erhält der Server über das Accept-Language-Headerfeld:

>GET / HTTP/1.1
>Host: debian.org
>Accept-Language: de,en
>
<HTTP/1.1 200 OK
<Content-Type: text/plain
<
<Deutsche Version

Üblicherweise werden mehrere von der ISO normierten Sprachen-Kürzel mit einem , (Komma) getrennt.

Keep-Alive

Mit Keep-Alive wird die Verbindung zum Server auch nach einem Request (samt Reply) offen gehalten. Dies ist besonders bei HTML-Seiten mit vielen Bildern sehr nützlich, da das Verbinden mit dem Server oftmals der längste Teil einer HTTP-Transaktion ist. Bei einer Seite mit 20 Bildern wären 21 Verbindungen erforderlich!

Bei HTTP/1.1 ist Keep-Alive standardmäßig aktiviert. Möchte man die Verbindung nach einem Request schließen, so muss man bei dem letzten Request explizit den Connection-Header benutzen:

>Connection: close
Ein letzter Request könnte also zum Beispiel so aussehen:
>GET /letztes-bild.png HTTP/1.1
>Host: der-server.org
>Connection: Close
>

Möchte man bei HTTP/1.0 Keep-Alive aktivieren, so kann man

>Connection: Keep-Alive
benutzen. Allerdings ist Keep-Alive bei HTTP/1.0 im Zusammenhang mit Proxies nicht zu empfehlen: Wenn die Proxy nicht aktiviertes Keep-Alive erkennt, so kann sie auch nicht das Ende einer Übertragung erkennen. Also würde der Proxy unbegrenzt lange (=bis der Timeout eintritt) auf die Antwort des Servers warten...

Jetzt gibt es allerdings en großes Problem: Wenn die Verbindung nicht geschlossen wird, woher weiß dann ein Client, dass die Seite fertig übertragen wurde? Eine einfache Antwort bietet der Content-Length-Header, der die Anzahl der Bytes der Übertragung angibt47.:

>HTTP/1.1 200 OK
>Content-Length: 12
>
>Hallo, Welt!

Chunked-Encoding

Bei CGI-Skripten kann der Server aber nicht wissen, wir groß die Seite ist, sie wird ja dynamisch generiert. Aber auch dazu gibt es eine Lösung: Chunked-Encoding. Bei diesem Verfahren wird eine Antwort in viele kleinere Teile zerlegt, wobei bei jedem kleineren Teil die Content-Length bekannt ist:

>GET / HTTP/1.1
>Host: somehost
>
>HTTP/1.1 200 OK
>Date: Thu, 07 Aug 2003 08:31:29 GMT
>Transfer-Encoding: chunked
>Content-Type: text/html
>
>ea1
>[Jetzt folgen ea1 (=3745 dezimal) Bytes]
>f7
>[Jetzt folgen nochmal f7 (=247 dezimal) Bytes]
>0
>

Auch kann ein Client, zum Beispiel via POST, Chunked-Encoding verwenden, mehr dazu [*].

Laut RFC 2616 muss jeder HTTP/1.1 Client und Server Chunked-Encoding unterstützen.

Partial Content

Manchmal möchte man nur einen bestimmten Bereich einer Datei herunterladen, zum Beispiel wenn ein Download abgebrochen wurde und dann später erneut aufgenommen werden soll. Dazu gibt es bei HTTP/1.1 den Range-Header:

>GET /proxy.log HTTP/1.1
>Host: mars
>
<HTTP/1.1 200 OK
<Content-Type: text/plain
<
<Server listening at port 8017
<Date ........................ Wed Aug  6 14:09:10 2003
<URL ......................... http://www.google.de:80/search
<
>GET /proxy.log HTTP/1.1
>Host: mars
>Range: bytes=17-42
>
<HTTP/1.1 206 Partial Content
<Accept-Ranges: bytes
<Content-Length: 26
<Content-Range: bytes 17-42/1158
<Content-Type: text/plain
<
<at port 8017
<Date ........

Cookies

Cookies, definiert in RFC 2109, können kleinere Informationen über den Benutzer speichern, zum Beispiel welche Waren sich in seinem E-Warenkorb seines E-Shops befinden.

Auch können sie jedem Benutzer eine von der IP unabhängige ID zuweisen, um jeden Benutzer bei einem späteren Besuch wiedererkennen zu können.

Cookies werden48 vom Server durch ein Headerfeld gesetzt (im Beispiel ein verbessertes Google):

>GET / HTTP/1.1
>Host: www.google.de
>
<HTTP/1.1 200 OK
<Date: Fri, 01 Aug 2003 09:17:00 GMT
<Content-Type: text/html
<Set-Cookie: PREF="ID=450b1d25610"; \
<  expires="Sun, 17-Jan-2038 19:14:07 GMT"; Path="/"; \
<  Domain=".google.de"; Version="1"
<
<<html><head>...
Durch den Set-Cookie-Header haben wir ein Cookie erhalten. Die durch das Cookie gesetzten Variablen sind:

Bei jedem weiteren Seitenabruf müssen alle für die jeweilige Seite relevanten (also nicht verfallene Cookies) Cookies mit dem Cookie-Headerfeld übertragen werden, und zwar genau so, wie man sie erhalten hat. Auch muss natürlich auf die Zugriffsbestimmungen geachtet werden.

Ein zweiter Request auf http://www.google.de/, muss dann also so aus sehen:

>GET / HTTP/1.1
>Host: www.google.de
>Cookie: PREF="ID=450b1d25610"; \
>  expires="Sun, 17-Jan-2038 19:14:07 GMT"; $Path="/"; \
>  $Domain=".google.de"; $Version="1"
>
<HTTP/1.1 200 OK
<Date: Fri, 01 Aug 2003 09:23:13 GMT
<Content-Type: text/html
<
<<html><head>...
Besonderen Variablen, wie Path, Domain und Version, muss dabei ein $ (Dollarzeichen) voranstehen. Die "`normalen"' Werte (PREF, expires) werden "`roh"' gespeichert.

Hier fällt auch auf, dass der Server nicht ein neues Cookie setzen will (Set-Cookie-Header fehlt). Das bedeutet also, dass Google uns nun "`kennt"'. Würden wir eine Einstellung verändern (Sprache, etc.) würden wir ein neues Cookie erhalten. Wenn wir dieses veränderte Cookie nicht mitschicken würden, so kämen wieder Googles Default-Einstellungen zum Einsatz.

Formulare

Oft sind auf einer Website Formulare zu finden, um zum Beispiel bei einer Umfrage abzustimmen oder dem Webmaster eine Nachricht zukommen zulassen. In (X)HTML realisiert sieht das zum Beispiel so aus:

<form action="http://host/umfrage.php" method="get">
  Name: <input type="text" name="name" /> <br />
  Alter: <input type="text" name="alter" /> <br />
  OS: <input type="text" name="os" /> <br />
  <input type="submit" value="Abschicken!" />
</form>

Die Übertragung solcher Formulare ist über zwei HTTP-Requests möglich: Den einfachen GET-Request50 und den etwas schwieriger verwendbaren POST-Request.

GET-Request

Der GET-Request ist ja schon vom "`normalen"' Abrufen von Websites bekannt, das heißt: Nichts neues Lernen!

Bei GET werden die Feldnamen von den Feldinhalten mit einem = getrennt, und dann an die URL, getrennt mit einem ?, angehängt. Die einzelnen Parameter unter sich werden mit einem & getrennt (siehe Grafik

Figure 19: Übertragung der Parameter bei GET-Formularen
\includegraphics[scale=0.6]{.cached/a0f40f52d8c1ff642100d2f01027fe8f.eps}
[*]).

Zusammenfassend wird

getrennt.

Auch hierzu mehr im Kapitel über die Automatisierung der ganzen Vorgänge [*].

POST-Request

Beim POST-Request werden die Felder nicht in der URL gespeichert, sondern im HTTP-Request selbst. Dies ermöglicht Übertragungen größer als einem Kilobyte.

Unser Beispielrequest sieht bei Verwendung von POST so aus:

>POST /umfrage.php HTTP/1.1
>Host: host
>Content-Type: application/x-www-form-urlencoded
>Content-Length: 29
>
>name=Ingo&alter=15&os=Gentoo
>
<HTTP/1.1 200 OK
<Date: Fri, 01 Aug 2003 10:17:48 GMT
<Content-Type: text/html
<
<<html>>...
Der Request ist also verlängert, nach der Leerzeile kommt nicht (wie etwa bei GET und HEAD) die Antwort, sondern der Inhalt des Formulars.

Wichtig ist auch der Content-Length-Header. Die Länge muss exakt mit der Anzahl der Zeichen der Übertragung übereinstimmen. Kennt man die Länge nicht, kann man auch hier Chunked-Encoding verwenden:

>POST /umfrage.php HTTP/1.1
>Host: host
>Content-Type: application/x-www-form-urlencoded
>Transfer-Encoding: chunked
>
>a
>name=Ingo&
>12
>alter=15&os=Gentoo
>0
>

Weiterleitung

Oft verweist eine Adresse auf eine andere, zum Beispiel verweist http://sf.net/ auf http://sourceforge.net/. Während dies zum einen mit Hilfe eines Meta-Feldes von (X)HTML möglich ist, ist die HTTP-Methode (verfügbar sowohl bei HTTP/1.0 als auch bei HTTP/1.1) wesentlich eleganter, da sie bei Dateien jedes Formats funktioniert, nicht nur bei HTML.

Erkennbar ist so eine Weiterleitung daran, dass statt des Statuscodes 200 302 zurückgeliefert wird. Im Location-Headerfeld wird dann die Zieladresse übermittelt.

Um also auf das Beispiel mit Sourceforge zurückzukommen:

HEAD-Request

Wenn der Inhalt einer Seite vollkommen uninteressant, nur der Header von Bedeutung ist, dann sehe ich keinen Zufall - dann erkenne ich die Bestimmung51 und verwende den HEAD-Request:

>HEAD / HTTP/1.1
>Host: hostname
>
<HTTP/1.1 200 OK
<Date: Fri, 18 Jul 2003 19:00:37 GMT
<Server: Apache/21.3.19 (GNU Gentoo/Hurd) mod_fastcgi/2.2.2 mod_dtcl
<Content-Type: text/html
<

Übersicht aller Befehle

Befehl Wirkung
GET /pfad Holt angegebene Datei
GET /pfad?feld1=name1&feld2=name2 Sendet Parameter via GET
HEAD /pfad Zeigt den Server-Header (Content-Type, etc.) einer Seite an

Typische Header-Felder sind
Header-Feld Bedeutung Wird gesendet vom
Host Hostname des Servers Client
Connection Keep-Alive benutzen? Client
Referer Zuletzt besuchte Seite Client
User-Agent Verwendeter Browser Client
Cookie Gesetzte Cookies Client
Accept-Language Gewünschte Sprachen Client
Server Benutzte Server-Software Server
Location Weiterleitung Server
Set-Cookie Cookie(s) setzen Server
Content-Type MIME-Typ der angeforderten Seite Server

Eine Beispielsitzung unter Verwendung der meisten Befehle und Header-Felder ist

Figure 20: HTTP at a glace
\begin{figure}\begin{center}\begin{small}
\begin{verbatim}POST /cgi-bin/login....
...
Eine Weiterleitung erfolgt...\end{verbatim}
\end{small}\end{center}\end{figure}
[*] zu sehen.



Footnotes

... HTTP37
Hypertext Transport Protocol
... URLs38
Uniform Ressource Locator
... Keep-Alive39
Auch HTTP/1.0 besitzt schon Keep-Alive, allerdings ist der Umgang mit Keep-Alive im Zusammenspiel mit (HTTP/1.0) Proxies sehr schwierig.
... HTTP-Proxies40
Proxies im Allgemeinen leiten en Traffic, den sie erhalten, mehr oder weniger gefiltert an das Ziel weiter. Die Antwort wird dann an den Client zurückgeschicht
... URIs41
Uniform Ressource Identifiers
... abgeschlossen42
Wir könnten hier, nach dem GET, auch noch weitere Headerfelder, wie zum Beispiel bei HTTP/1.1 das Host-Feld oder den Referer (siehe dazu [*]), unterbringen
...proxy.as-netz.de:808043
Diese Schreibweise wird oft verwendet, da sie sowohl den Hostnamen als auch den zu verwendenen (TCP-)Port angibt.
... Gründen44
muhahaha... ;-)
... nicht45
Oft wird man zur Homepage weitergeleitet
...10.0.0.346
Natürlich können alle Header gefälscht sein - Merke: Traue nichts, was nicht signiert ist!
... angibt47
Im Beispiel ist die Zeile übrigens nicht nicht mit EOL terminiert.
... werden48
von JavaScript-Idiotie einmal abgesehen...
... sind49
Wen es jetzt wundert, warum das Cookie am 17. Januar 2038 ("`krumme"' Zahl) abläuft und nicht zum Beispiel am 1. Januar 2010 ("`gerade"' Zahl), der muss wissen, wie Unix intern seine Uhr verwaltet: Unix zählt die Anzahl der Sekunden seit dem 1. Januar 1970, 0 Uhr GMT. Diese Anzahl hält Unix in einem 32-Bit breitem Register fest. Und die damit höchste darstellbare Zahl, 2147483647, zurück in "`unser"' System umgerechnet, ist genau der 17. Januar 2038. Eine Sekunde später ist für Unix wieder der 1. Januar 1970.
...-Request50
bei dem allerdings die maximale Länge der Formulardaten (eigentlich der gesamten URL) nicht mehr als 1024 Zeichen betragen darf
... Bestimmung51
MATRIX...

Hosted at Sorceforge.net next up previous contents
Next: Gopher Up: Hitchhiker's Guide to the Previous: NNTP   Contents
Ingo Blechschmidt 2003-08-07