0%

Kapitel 2

Um einen Protokollwechsel bitten

Eine Upgrade-Anfrage lesen

Eine beginnt ihr Leben als -Anfrage. Der Client öffnet eine , sendet ein GET mit ein paar zusätzlichen Headern und bittet den Server, auf dieser Verbindung kein HTTP mehr zu sprechen und auf das WebSocket-Protokoll umzustellen. Wenn der Server zustimmt, sagt er das in einer Antwort, und von da an trägt dieselbe Verbindung WebSocket-Nachrichten in beide Richtungen. Dieser Austausch heißt , und in diesem Kapitel schreibst du beide Seiten davon.

Hier ist die Anfrage, die ein Client sendet. Es ist das Beispiel aus RFC 6455, dem Dokument, das das WebSocket-Protokoll definiert, aus seinem Abschnitt 1.3:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

Wie bei jeder HTTP-Anfrage, die du in HTTP with Python geschrieben hast, endet jede Zeile mit \r\n, und eine Leerzeile beendet den Kopf. Mit diesen Zeilenenden und der Leerzeile ist diese Anfrage 230 Bytes lang. Sie hat keinen Body.

Zeile für Zeile

Die erste Zeile ist eine Anfragezeile wie jede andere: die GET, das Ziel /chat und die Version HTTP/1.1. RFC 6455 verlangt die Methode GET und HTTP-Version 1.1 oder höher, und in der Praxis ist die Version immer HTTP/1.1.

Host: server.example.com nennt den Server, für den die Anfrage bestimmt ist. HTTP/1.1 verlangt ihn in jeder Anfrage, aus dem Grund, den du in HTTP with Python kennengelernt hast: Eine Adresse kann viele Websites bedienen, und der Server muss wissen, welche der Client gemeint hat.

Upgrade: websocket nennt das Protokoll, auf das der Client umstellen möchte. Upgrade ist ein gewöhnlicher für jeden Protokollwechsel; das Token websocket sagt, für welchen.

Connection: Upgrade sagt dem Server, dass diese Verbindung selbst auf den Upgrade-Header reagieren soll. Der Connection-Header enthält eine durch Kommas getrennte von Tokens, und ein Client darf neben Upgrade noch andere aufführen. Viele Clients senden Connection: keep-alive, Upgrade, und das bittet genauso um das Upgrade, in beliebiger Reihenfolge. Entscheidend ist, dass Upgrade eines der Tokens ist.

Sec-WebSocket-Key enthält 16 zufällige Bytes, in geschrieben, der Kodierung, die du in HTTP with Python verwendet hast, um Bytes als Header-Text zu transportieren. Der Client wählt für jede Anfrage einen neuen Schlüssel; RFC 6455 verlangt das. Die Antwort des Servers muss einen enthalten, der aus diesem Schlüssel berechnet wird, und Lektion 3 berechnet ihn.

Sec-WebSocket-Version: 13 ist die Version des WebSocket-Protokolls, die der Client spricht. Version 13 ist die, die RFC 6455 definiert; Entwürfe, die davor geschrieben wurden, verwendeten andere Nummern.

Header-Namen werden ohne Rücksicht auf Groß- und Kleinschreibung verglichen, wie in jeder HTTP-Nachricht, also bedeutet upgrade: WebSocket dasselbe wie Upgrade: websocket. Die beiden Tokens werden genauso verglichen: websocket in Upgrade und Upgrade in Connection dürfen in jeder Mischung aus Groß- und Kleinbuchstaben ankommen.

Der Schlüssel sieht aus wie ein Geheimnis, ist aber keins. Dekodiere ihn und sieh dir an, was die Autoren des RFC hineingesteckt haben:

Try it

Es gibt b'the sample nonce' und 16 aus. Eine Nonce ist ein Wert, der nur einmal verwendet wird. Was auch immer seine 16 Bytes sind, der Schlüssel reist offen sichtbar. Seine Aufgabe ist es, jede Anfrage verschieden zu machen, sodass die daraus berechnete Antwort zu dieser Anfrage gehört und zu keiner anderen.

Diese Antwort macht den Handshake vertrauenswürdig. Ein Server, der WebSocket spricht, berechnet aus dem Schlüssel einen Wert und sendet ihn zurück. Ein Server oder ein Cache dazwischen, der WebSockets nicht versteht, kann diesen Wert nicht erzeugen, also weiß ein Client, der den richtigen Wert erhält, dass seine Anfrage als WebSocket-Anfrage verstanden und nicht mit einem gewöhnlichen GET verwechselt wurde. Der Schlüssel verschlüsselt nichts, das ist die Aufgabe von , und er sagt nichts darüber, wer der Benutzer ist.

Zwei Header, die dieser Kurs weglässt

Zwei Zeilen des Beispiels sind optional, und der Server dieses Kurses braucht sie nicht.

Origin: http://example.com nennt die Webseite, deren Skript die Verbindung geöffnet hat. Ein Browser sendet ihn immer; ein Python-Client wie der, den du in Lektion 5 schreibst, darf ihn weglassen. Ein Server kann ihn verwenden, um Verbindungen von Seiten abzulehnen, denen er nicht vertraut, und Kapitel 9 zeigt, wie. Bis dahin ignoriert dein Server ihn.

Sec-WebSocket-Protocol: chat, superchat bietet eine Liste von Subprotokollen an, Sprachen auf Anwendungsebene, die der Client über den WebSocket sprechen könnte, und lässt den Server eines wählen. Im Beispiel des RFC nennt die Antwort des Servers chat. Dieser Kurs definiert seine eigenen Nachrichten und handelt kein Subprotokoll aus, also sendet dein Server diesen Header nie, und dein Client fragt nie danach.

Was nach der Anfrage passiert

Wenn die Anfrage akzeptabel ist, antwortet der Server mit dem Status 101 Switching Protocols, einigen Headern und einer Leerzeile, und sonst nichts. Nach dieser Leerzeile ist HTTP auf dieser Verbindung vorbei. Dieselbe TCP-Verbindung bleibt offen, und beide Seiten senden jetzt WebSocket-, in beide Richtungen, wann immer sie etwas zu sagen haben. Folge den beiden Linien im Bild nach unten: Sie brechen nie ab, weil die Verbindung, die den HTTP-Austausch getragen hat, auch die Frames trägt.

Eine HTTP-Anfrage und eine 101-Antwort stellen die Verbindung um, und nach der Leerzeile trägt dieselbe Verbindung Frames in beide Richtungen.

In Worten: Der Client sendet die Upgrade-Anfrage, GET /chat HTTP/1.1 mit den Headern Upgrade, Connection, Schlüssel und Version; der Server antwortet mit HTTP/1.1 101 Switching Protocols, die den aus dem Schlüssel berechneten Wert trägt, und von da an fließen Frames in beide Richtungen auf derselben Verbindung, ohne Paarung von Anfrage und Antwort. Wenn die Anfrage nicht akzeptabel ist, antwortet der Server stattdessen mit einem gewöhnlichen HTTP-Fehler, und es findet keine Umstellung statt. Lektion 4 entscheidet, welcher Fall vorliegt.

Welchen dieser Header aus dem Beispiel könnte ein Client weglassen und trotzdem eine 101 vom Server dieses Kurses bekommen?

Eine Anfrage trägt Connection: keep-alive, Upgrade. Bittet sie um das Upgrade?

Wofür ist Sec-WebSocket-Key da?

Du kannst jetzt jede Zeile einer Upgrade-Anfrage lesen und sagen, warum sie da ist. In der nächsten Lektion öffnest du das Projekt des Kapitels und machst aus diesen Bytes ein , das dein Server prüfen kann.