Kapitel 2
Um einen Protokollwechsel bitten
Eine Upgrade-Anfrage lesen
Eine 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
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 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 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
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:
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
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 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