5 Hypertext Transfer Protocol (HTTP) Aus der Definition von HTTP/1.1 (RFC 2616): The Hypertext Transfer Protocol (HTTP) is an application-level protocol for distributed, collaborative, hypermedia information systems. It is a generic, stateless, protocol which can be used for many tasks beyond its use for hypertext, such as name servers and distributed object management systems, through extension of its request methods, error codes and headers. A feature of HTTP is the typing and negotiation of data representation, allowing systems to be built independently of the data being transferred. Vorläufige Version 236 c 2003 Peter Thiemann Beispiel für HTTP Kommunikation Aufbau der Verbindung zum WWW-Server [hanauma] 107 > telnet localhost www TCP/IP Verbindung zum Rechner localhost an den Port www (80) Antwort von Telnet Trying 127.0.0.1... Connected to localhost. Escape character is ’^]’. Anfrage (Request) an den WWW-Server 1|GET / HTTP/1.1 2|Host: localhost 3| Request besteht nur aus Kopf (Header), der Rumpf (Body) ist leer Vorläufige Version 237 c 2003 Peter Thiemann Kopf (Header) der Antwort 1|HTTP/1.1 200 OK 2|Date: Wed, 03 May 2000 19:41:20 GMT 3|Server: Apache/1.3.9 (Unix) 4|Last-Modified: Wed, 20 May 1998 14:59:42 GMT 5|ETag: "4405-656-3562efde" 6|Accept-Ranges: bytes 7|Content-Length: 1622 8|Content-Type: text/html 9| Leerzeile signalisiert das Ende des Headers Rumpf (Body) der Antwort in diesem Fall ein HTML-Dokument <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <HTML> <HEAD> <TITLE>Test Page for Apache Installation on Web Site</TITLE> </HEAD> <!-- ... --> </HTML> Vorläufige Version 238 c 2003 Peter Thiemann Nach kurzer Wartezeit beendet der Server die Verbindung. Connection closed by foreign host. Alternativ: weitere Requests über die gleiche Verbindung Vorläufige Version 239 c 2003 Peter Thiemann Format einer Anfrage hRequest i ::= hRequest-Line i ∗ hgeneral-header i | hrequest-header i | hentity-header i hCRLF i hCRLF i [hmessage-body i] Jede Zeile wird durch hCRLF i, CR (ASCII-Kode 13) gefolgt von LF (ASCII-Kode 10), abgeschlossen. Vgl. Methodenaufruf • erste Zeile (hRequest-Line i): Name der Methode und vorgeschriebene Parameter • Headerzeilen: weitere (optionale) Parameter, durch Schlüsselworte identifiziert • Rumpf: optionaler Inhalt der Anfrage (Parameter) Vorläufige Version 240 c 2003 Peter Thiemann Erste Zeile einer Anfrage hRequest-Line i hMethod i ::= hMethod i hRequest-URI i hHTTP-Version ihCRLF i ::= GET * Anfordern eines Dokuments | HEAD * Anfordern der Header eines Dokuments | POST Senden einer Anfrage | PUT Ablegen eines Dokuments | DELETE Löschen eines Dokuments | TRACE Anfordern der empfangenen Anfrage | OPTIONS * Vorläufige Version erforderliche Methoden 241 c 2003 Peter Thiemann Vorläufige Version hRequest-URI i ::= habs path i | habsoluteURI i | . . . hHTTP-Version i ::= HTTP/1.1 habs path i ::= / [hpath i] [;hparams i] [?hquery i] hparams i ::= ... hquery i ::= ... 242 c 2003 Peter Thiemann Beispiel (Minimalanfrage) 1|GET / HTTP/1.1 2|Host: www.informatik.uni-freiburg.de 3| Vorläufige Version 243 c 2003 Peter Thiemann Format einer Header-Zeile hheader i ::= hkey-token i:hvalue i Beispiel hHost i Vorläufige Version ::= Host: hhost i [ : hport i ] 244 c 2003 Peter Thiemann Anfragespezifische Header hrequest-header i ::= hAccept i media types | hAccept-Language i | hHost i * Hostname des Servers | hReferer i URL | hUser-Agent i .. . * Vorläufige Version in jeder direkten Anfrage erforderlich 245 c 2003 Peter Thiemann Allgemeine Header Können in Anfragen und Antworten benutzt werden, meist optional hgeneral-header i ::= hConnection i | hDate i | hTransfer-Encoding i + persistent/one-shot +! + + häufig in Antworten benutzt +! in jeder Antwort erforderlich Entity Header Information über den hmessage-body i, falls vorhanden: Content -Encoding, -Language, -Length, -Location, . . . Vorläufige Version 246 c 2003 Peter Thiemann Format einer Antwort hResponse i ::= hStatus-Line i ∗ hgeneral-header i | hresponse-header i | hentity-header i hCRLF i hCRLF i [hmessage-body i] Beispiel 1|HTTP/1.1 200 OK 2|Date: Wed, 03 May 2000 19:41:20 GMT 3|Server: Apache/1.3.9 (Unix) 4|Last-Modified: Wed, 20 May 1998 14:59:42 GMT 5|ETag: "4405-656-3562efde" 6|Accept-Ranges: bytes 7|Content-Length: 1622 8|Content-Type: text/html 9| Vorläufige Version 247 c 2003 Peter Thiemann Statuszeile hStatus-Line i ::= hHTTP-Version i hStatus-Code i hReason-Phrase ihCRLF i hHTTP-Version i ::= HTTP/1.1 hStatus-Code i ::= hdigit ihdigit ihdigit i hReason-Phrase i ::= Text ohne hCRLF i Interpretation des Status-Code 1xx Informational – Request received, continuing process 2xx Success – The action was successfully received, understood, and accepted 3xx Redirection – Further action must be taken in order to complete the request 4xx Client Error – The request contains bad syntax or cannot be fulfilled 5xx Server Error – The server failed to fulfill an apparently valid request • Siehe RFC 1700 für alle reservierten hStatus-Code is und hReason-Phrase is • hReason-Phrase is sind nur Empfehlungen, können von Server und Client ignoriert und/oder geändert werden • Im Fehlerfall enthält hmessage-body i oft weitere Erklärung Vorläufige Version 248 c 2003 Peter Thiemann Inhalt der Nachricht • beliebige Folge von Oktetts • falls hContent-Type i nicht vorhanden – Client darf aufgrund der URI raten – falls erfolglos application/octetstream • hContent-Encoding i: gzip, compress, deflate beschreiben Kodierungseigenschaften des ursprünglichen Objekts • hTransfer-Encoding i definiert Übertragungskodierung: chunked, gzip, compress, deflate, identity Vorläufige Version 249 c 2003 Peter Thiemann Transfer-Encoding: identity and chunked identity hContent-Length i Header definiert die Länge des hmessage-body i in octets; hmessage-body i ist Folge von octets dieser Länge (danach folgt unvermittelt die nächste Antwort bzw Verbindungsabbruch) chunked wird verwendet, wenn die Länge nicht a-priori feststeht. hmessage-body i wird in chunks übertragen (verkürzt): Chunked-Body = *chunk last-chunk CRLF chunk chunk-size last-chunk chunk-data Vorläufige Version = chunk-size CRLF chunk-data CRLF = 1*HEX = 1*("0") CRLF = chunk-size(OCTET) 250 c 2003 Peter Thiemann 6 Common Gateway Interface (CGI) CGI (Common Gateway Interface) Skripte erlauben die dynamische Erzeugung von Dokumenten auf dem Server. Typische Anwendung: CGI-Skripte verarbeiten Eingaben aus Formularen und erzeugen in Abhängigkeit von den Eingaben ein Antwortdokument. Eigenschaften von CGI: Einfachheit Sprachunabhängigkeit Sicherheit durch separaten Prozess Offener Standard Architekturunabhängigkeit Vorläufige Version 251 c 2003 Peter Thiemann HTTP−Request HTTP−Client (Browser) HTTP−Response HTTP−Server stdout stdin, env CGI Prozeß Vorläufige Version 252 c 2003 Peter Thiemann Ausführung eines CGI-Skripts • Server erkennt CGI-Skripte an der URL – spezielles Element im Pfad (z.B. cgi-bin), dann nächstes Pfadelement = Name eines ausführbaren Programms in konfigurierbarem Verzeichnis – spezielle Extension am Dateinamen (z.B. .cgi) = Name eines ausführbaren Programms • Server verarbeitet den Header des HTTP-Requests • Legt Request-Information in Environment ab (Prozessumgebung) • Generiert die Statuszeile und einige Response-Header (Date, Server, Connection) • Schliesst den Headerteil der Response NICHT ab • Startet das CGI-Programm mit – Standardausgabe ⇔ Versenden an Client/Browser – Standardeingabe ⇔ ggf. Lesen vom Client/Browser – Argumente ⇔ Pfadelemente nach dem Namen des CGI-Programms – Umgebung definiert weitere Parameter der Anfrage Vorläufige Version 253 c 2003 Peter Thiemann Pflichten eines CGI-Programms • Interpretation der Parameter und der Anfrage • Drucken weiterer Headerzeilen (Content-Length, Content-Type, Content-Encoding, . . .) • Abschliessen des Headerteils der Response durch Leerzeile • Generieren des Inhaltes Sprachen zur CGI-Programmierung • Jede geeignet, die Standardeingabe und Umgebungsvariable lesen kann, sowie Standardausgabe schreiben kann • Für Java ist ein wrapper Programm zum Lesen der Umgebungsvariablen erforderlich • Manche Webserver beinhalten Interpreter für Skriptsprachen (perl, php, etc), um die Startzeit für einen externen Interpreter zu sparen Beispiel: Apache Module mod perl, mod php, mod python, mod ruby, . . . Vorläufige Version 254 c 2003 Peter Thiemann 6.1 Parameter für ein CGI-Programm Die Einsendung eines XHTML Formulars liefert Feldname1 =Wert1 Feldname2 =Wert2 ... Feldnamek =Wertk wobei Feldnamen wiederholt auftreten können. Feldnamen und Werte werden vor Übertragung vom Browser kodiert Standardkodierung: URL Kodierung application/x-www-form-urlencoded • Buchstaben und Zahlen bleiben erhalten • Leerzeichen werden durch + ersetzt • Alle weiteren Zeichen werden durch %hASCII-code i ersetzt (in zweistelliger Hexadezimaldarstellung) vgl. public static String java.net.URLEncoder.encode(String s) Vorläufige Version 255 c 2003 Peter Thiemann 6.2 Zugriffsmethoden GET Kodierung der Anfrage in der URL durch Anhängen eines hQuerystring i der Form ?hFeld-Wert-Liste i an die action URL hFeld-Wert-Liste i ::= hkodierter-Feldname i=hkodierter-Wert i ∗ &hkodierter-Feldname i=hkodierter-Wert i Der Webserver legt den hQuerystring i in der Umgebungsvariable QUERY STRING ab. POST verschickt die hFeld-Wert-Liste i im hmessage-body i der Anfrage. Der Webserver speichert die Länge (in Octets) des hmessage-body i in der Umgebungsvariable CONTENT LENGTH. Das CGI-Programm muss genau so viele Octets lesen und interpretieren (nicht bis Dateiende lesen!) Durch URL Kodierung werden • unerlaubte Zeichen in URLs vermieden • die Zeichen = und & in Feldnamen und Werten verwendbar Rationale für Methoden: GET beobachtet, POST ändert ggf. Zustand des Servers Vorläufige Version 256 c 2003 Peter Thiemann Ein Shellskript als CGI-Skript: date Abspeichern als date.cgi oder als /cgi-bin/date. #!/bin/sh echo Content-type: text/html echo cat <<EOF <HTML><head><title>Date and Time</title></head> <body> <h1>Date and Time</h1> EOF /bin/date cat <<EOF <p> <a href="/index.html">Back home</a> </body></html> EOF Vorläufige Version 257 c 2003 Peter Thiemann Dito in Haskell import Time main = do putStrLn "Content-Type: text/html" putStrLn "" putStrLn "<HTML><head><title>Date and Time</title></head>\ \<body> <h1>Date and Time</h1>" clkt <- getClockTime calt <- toCalendarTime clkt putStrLn (calendarTimeToString calt) putStrLn "<p>\ \<a href=\"/index.html\">Back home</a>\ \</body></html>" Vorläufige Version 258 c 2003 Peter Thiemann Dito in WASH import CGI import Time main = do clkt <- getClockTime calt <- toCalendarTime clkt let str = calendarTimeToString calt run $ standardQuery "Date and Time" $ do text str <p><a href="/index.html">Back home</a></p> Vorläufige Version 259 c 2003 Peter Thiemann RawCGI • Teil von WASH • Nur Dekodierung der Parameter type CGIProgram = CGIInfo -> CGIParameters -> IO () -- |low level info type CGIInfo = ... -- |decoded parameters type CGIParameters = [(String, String)] -- |low level options, empty list is usually ok type CGIOptions = [...] -- |run a CGI program start :: CGIOptions -> CGIProgram -> IO () Vorläufige Version 260 c 2003 Peter Thiemann Simple Use of RawCGI import RawCGI main = start [] mycgi -- |display all form parameters mycgi info params = do putStrLn "Content-Type: text/plain" putStrLn "" putStrLn "My parameters are:" mapM_ oneBinding params oneBinding (name, value) = do putStr name putStr " = " putStrLn value Vorläufige Version 261 c 2003 Peter Thiemann 6.3 Umgebungsvariablen im CGI-Skript: test-cgi #!/bin/sh # disable filename globbing set -f echo Content-type: text/plain echo echo CGI/1.0 test script report: echo echo argc is $#. argv is "$*". echo echo SERVER_SOFTWARE = $SERVER_SOFTWARE echo SERVER_NAME = $SERVER_NAME echo GATEWAY_INTERFACE = $GATEWAY_INTERFACE echo SERVER_PROTOCOL = $SERVER_PROTOCOL echo SERVER_PORT = $SERVER_PORT echo REQUEST_METHOD = $REQUEST_METHOD echo HTTP_ACCEPT = "$HTTP_ACCEPT" echo PATH_INFO = "$PATH_INFO" Vorläufige Version 262 c 2003 Peter Thiemann echo echo echo echo echo echo echo echo echo PATH_TRANSLATED = "$PATH_TRANSLATED" SCRIPT_NAME = "$SCRIPT_NAME" QUERY_STRING = "$QUERY_STRING" REMOTE_HOST = $REMOTE_HOST REMOTE_ADDR = $REMOTE_ADDR REMOTE_USER = $REMOTE_USER AUTH_TYPE = $AUTH_TYPE CONTENT_TYPE = $CONTENT_TYPE CONTENT_LENGTH = $CONTENT_LENGTH Aufrufendes Formular <form action="/cgi-bin/test-cgi/extra/parameters" method="get"> <input type="text" name="text=1" value="value for text=1"> <input type="text" name="text=2" value="nothing really+&!"> <input type="submit"> </form> Vorläufige Version 263 c 2003 Peter Thiemann Ausgabe von test-cgi CGI/1.0 test script report: argc is 0. argv is . SERVER_SOFTWARE = Apache/1.3.9 (Unix) SERVER_NAME = hanauma.informatik.uni-freiburg.de GATEWAY_INTERFACE = CGI/1.1 SERVER_PROTOCOL = HTTP/1.0 SERVER_PORT = 80 REQUEST_METHOD = GET HTTP_ACCEPT = image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */* PATH_INFO = extra/parameters PATH_TRANSLATED = /usr/local/www/data/extra/parameters SCRIPT_NAME = /cgi-bin/test-cgi QUERY_STRING = text%3D1=value+for+text%3D1&text%3D2=nothing+really%2B%26%21 REMOTE_HOST = REMOTE_ADDR = 127.0.0.1 REMOTE_USER = AUTH_TYPE = CONTENT_TYPE = CONTENT_LENGTH = Vorläufige Version 264 c 2003 Peter Thiemann 6.4 File Upload Wert eines Eingabefeldes ist Inhalt einer Datei Probleme: • Dateigröße macht Anhängen an URL unmöglich • Dateiinhalt überwiegend nicht-ASCII: URL Kodierung expandiert die Größe um Faktor 3 • Übertragung von Metadaten, wie Dateiname, content type, etc Lösung: Verwendung von (Attributen von <form>) • method="POST" • enctype="multipart/form-data" (neuer MIME-Typ RFC 1521) Vorläufige Version 265 c 2003 Peter Thiemann Beispiel <FORM ENCTYPE="multipart/form-data" ACTION="/cgi-bin/test-cgi" METHOD=POST> File to process: <INPUT NAME="userfile1" TYPE="file"> <INPUT TYPE="submit" VALUE="Send File"> </FORM> Verschickt Anfrage mit Header Content-type: multipart/form-data; boundary=hboundary-string i hboundary-string i soll nicht in den Felddaten vorkommen Der hmessage-body i wiederholt --hboundary-string i Content-Disposition: form-data; name="hFeldname i"[; filename="hDateiname i"] Content-Type: hcontent type i hInhalt des Feldes i und endet mit --hboundary-string i-Vorläufige Version 266 c 2003 Peter Thiemann Mehrere Selektionen in einem Feld (Feld Header) hboundary-string i Content-Disposition: form-data; name="hFeldname i" Content-Type: multipart/mixed; boundary=hinterner boundary-string i hInhalt i Inhalt eines multipart/mixed Feldes • Wiederholung von --hinterner boundary-string i Content-disposition: attachment; filename="file1.txt" Content-Type: hcontent-type i h... Inhalt von file1.txt ... i • Beenden mit --hinterner boundary-string i-- Vorläufige Version 267 c 2003 Peter Thiemann Kodierung von Nicht-ASCII Zeichen (RFC 1522) in Feldnamen hencoded-word i ::= =?hcharset i?hencoding i?hencoded-text i?= hcharset i ::= ISO-8859-1 | . . . hencoding i ::= B|Q • Falls hencoding i = B, so ist hencoded-text i mit base64 (RFC 1521) kodiert. • Falls hencoding i = Q, so ist hencoded-text i mit quoted-printable (RFC 1521) kodiert. Vorläufige Version 268 c 2003 Peter Thiemann