Tim Tepaße: Das bisschen Klebstoff, das das Web zusammen hält

Beitrag lesen

Hallo,

Formularfeldinhalte außerhalb von ASCII lassen sich doch problemlos URL-Gerecht kodiert übertragen - wieso sollte ein Browser das mit Feldnamen, die nicht-ASCII-Zeichen enthalten, nicht ebenso handhaben?

Otto von Lottototto bastelt sich eine Webseite mit einem simples Formular:

<form action="http://example.org/test" method="get">  
<p><label>Eingabe</label>: <input name="Δ"></p>  
</form>

(Aus irgendwelchen Gründen ist Otto der Meinung, dass das Zeichen Δ der richtige Bezeichner für dieses Formular sei.)

Nun tippt Ava Thalassa in diesen Textfeld die Eingabe "32 ms." ein und haut in ihrem Browser auf Return. Der Browser muss nun reagieren.

Versetzen wir uns mal in die Lage desjenigen, der für das Stück Code im Browser zuständig ist, der dies regelt. Er beginnt mit dem Event des Auslösens des Formulars. Nun schaut er in den HTML Standard, wie vorzugehen sei. Schritt eins und zwei sind bequem zu händeln. Schritt drei wird übersprungen, es gibt kein Attribut namens „enctype“, ausserdem ergibt sich das aus dem Kontext von Schritt vier. Nur ist dieser etwas schwieriger.

„If the method is "get" and the action is an HTTP URI, the user agent takes the
  value of action, appends a `?' to it, then appends the form data set, encoded
  using the "application/x-www-form-urlencoded" content type. (...) In this
  scenario, form data are restricted to ASCII codes.

Als erstes bastelt er sich also aus den jeweiligen Werten eine Abfolge von Charaktern:

http://example.org/test?∆=32 ms.

Das ist noch keine URI. Sie ist noch nicht in dem Typ x-www-form-urlencoded. Also guckt er nach, wie er dies macht:

„application/x-www-form-urlencoded
  This is the default content type. Forms submitted with this content type must
  be encoded as follows:
  Control names and values are escaped. Space characters are replaced by +',   and then reserved characters are escaped as described in [RFC1738], section   2.2: Non-alphanumeric characters are replaced by %HH', a percent sign and two
  hexadecimal digits representing the ASCII code of the character. Line breaks
  are represented as "CR LF" pairs (i.e., %0D%0A'). The control names/values   are listed in the order they appear in the document. The name is separated   from the value by =' and name/value pairs are separated from each other by `&'.“

Aha. Sieht ja relativ einfach aus. Nun guckt er noch in referenzierten RFC 1738 nach, in Sektion 2.2:

„In most URL schemes, the sequences of characters in different parts
  of a URL are used to represent sequences of octets used in Internet
  protocols.“
  (...)
  „URLs are written only with the graphic printable characters of the
  US-ASCII coded character set. The octets 80-FF hexadecimal are not
  used in US-ASCII, and the octets 00-1F and 7F hexadecimal represent
  control characters; these must be encoded.“

Gut denkt er. Ich haben einen haufen von Unicode Charaktern. Jetzt muss ich diese nur noch in Oktetts („Bytes“) umwandeln, wo nötig, und diese dann hexadezimal repräsentieren. Das Tolle ist: Es ist nirgendwo nötig, wenn man in die Details einsteigt, nur beim Delta:

Das Zeichen Δ hat den Unicode Code Point U+0394 und heisst GREEK CAPITAL LETTER DELTA. Es ist nicht in US-ASCII enthalten. Es ist auch nicht in ISO 8859-1 enthalten. Es ist in ISO-8859-7 enthalten, dort hat es den hexadezimalen Code C4, also kann man es durch das Oktett 0xC4 repräsentieren. Und natürlich ist es in den verschiedenen Unicode Kodierungen enthalten, die alle verschiedene Varianten von Oktetts auspucken. Nur: welche Kodierung nimmt unser Browserprogrammierer nun?

Latin 7 – 0xC4       – "http://example.org/test?%C4=32+ms."
UTF-8   – 0xCE94     – "http://example.org/test?%CE%94=32+ms."
UTF-16  – 0x0394     – "http://example.org/test?%03%94=32+ms."
UTF-32  – 0x00000394 – "http://example.org/test?%00%00%03%94=32+ms."

... und wenn man weiter in exotischeren Zeichensätzen sucht, findet man noch mehr Möglichkeiten. Für welche Möglichkeit entscheidet sich nun unser Programmierer? Der veraltete RFC 1738 sagt nichts normatives dazu. Dessen Nachfolger RFC 2396 auch nicht. Dessen Nachfolger (und aktueller Standard) RFC 3986 auch nicht. Auch nicht RFC 2616, zuständig für HTTP, ausser dass eine URI gefälligst nur aus Zeichen aus US-ASCII zu bestehen habe. Nein, auch in keinem (X)HTML-Standard.

Es gibt die Aussage, dass die nicht in der in URIs erlaubten Teilmenge von US-ASCII ausdrückbaren Zeichen als Oktetts zu kodieren habe. Es gibt aber keinen Hinweis, welche Textkodierung man nutzen soll, um aus Zeichen Oktetts zu kriegen.

Locker, flockig, wie unser Kerl drauf ist (ein Snowboarder), entscheidet er sich für UTF-8, schließlich wird das überall empfohlen. Ohne es zu wissen, behandelt er seine Abfolge von Zeichen als IRI, für die es eine standardisierte Umwandlung zu URIs gibt, nämlich UTF-8 als Konversion von Zeichen zu hexadezimaler Textdarstellung von Oktetts zu benutzen. Allerdings: IRIs werden streng genommen nirgendwo in HTML oder HTTP erwähnt. Trotzdem ist es inzwischen (schon allein wegen IDNs) der Defakto-Standard geworden. Es ist zumindest das vernünftigste, was man inzwischen machen kann.

Nur: Nicht jeder Browser machte das. Früher wurde auch gerne Latin 1 verwendet, bot sich ja an, „hohe Bytes“ bedeutet ISO 8859 undsoweiter. Ich meine mich zu erinnern, dass der IE noch eine Option namens „URLs immer als UTF-8 senden“ hat. Mich schaudert die Implikation von „immer“. Was wäre denn das Gegenteil? „Manchmal als UTF-8 senden“? Zeichen, die in Latin-1 drin sind als Latin 1 kodieren und senden, Unicode als UTF-8? Und was dann bitte bei Vollmond?

Zugegeben, in den aktuellen guten Browsern ist das kein tatsächliches Problem mehr; ich schreibe wieder viel zu viel über ein aberwitziges Detail. Aber nicht jeder benutzt diese. Und letztendlich gibt es da keine richtige Spezifikation zu, man kann es nur „richtig“ machen, wenn man eine Spezifikation benutzt, die es erst seit anderthalb Jahre gibt. „Problemlos“ finde ich das aber nicht. ;)

Tim

--
Quizfrage für Fortgeschrittene: Was passiert, wenn die Anfrage nach der URI http://people.example.org/ren%C3%A9 bei einem Server landet, in dessen Dateisystem Dateinamen in ISO 8859-1 abgespeichert sind?