Zusammenfassung

  • RFC 6455 startete WebSocket mit HTTP/1.1-GET, Upgrade und einer 101-Antwort. RFC 7540 entfernte diesen Wechsel der ganzen Verbindung aus HTTP/2, dessen Streams sich eine Verbindung teilen.
  • RFC 8441 führte erweitertes CONNECT mit :protocol = websocket, :scheme und :path ein. Der Client darf es erst nach SETTINGS_ENABLE_CONNECT_PROTOCOL = 1 vom Server einsetzen. Die IANA führt die Einstellung unter 0x8 mit Anfangswert 0.
  • Der akzeptierte Stream trägt WebSocket-Frames neben gewöhnlichem HTTP/2-Verkehr. Connection, Upgrade und die Verarbeitung von Sec-WebSocket-Key/Accept fallen bei diesem Start weg; innerhalb des Tunnels läuft WebSocket weiter.

Ein Schalter für das ganze Haus

Das WebSocket-Protokoll von 2011 begann als HTTP/1.1-Anfrage. Der Client schickte GET mit Upgrade: websocket und Connection: Upgrade. Antwortete der Server mit 101 Switching Protocols, wurde die TCP-Verbindung zum Kanal für beide Richtungen. Solange eine Verbindung eine Anfrage bediente, ließ sich die ganze Leitung ohne große Nebenwirkungen an das Gespräch übergeben.

HTTP/2 machte aus der Leitung eine gemeinsame Ressource. Eine Seite kann Bilder empfangen, während eine andere Funktion auf Nachrichten wartet. RFC 7540 entfernte die 101-Antwort aus HTTP/2: Ein Protokollwechsel für die gesamte Verbindung würde die anderen Streams treffen. Upgrade und Connection beschreiben die gemeinsame Leitung, keinen einzelnen Stream. Der alte WebSocket-Schlüssel passte deshalb nicht mehr zur neuen Tür.

Das Problem war praktisch, bevor überhaupt eine Nachricht gesendet wurde. Für die Seite stand bereits eine HTTP/2-Verbindung, doch ihr Echtzeitkanal brauchte eine andere Öffnung. Eine zweite Verbindung allein für den alten Handschlag hätte die gemeinsame Nutzung umgangen. Den 101-Wechsel in die bestehende Verbindung zu pressen hätte die Nachbarn verdrängt. RFC 8441 änderte die Größe dessen, was ein WebSocket anfordern durfte.

Der Server muss zuerst zustimmen

Der Server kündigt SETTINGS_ENABLE_CONNECT_PROTOCOL = 1 an. Im HTTP/2-Register der IANA hat die Einstellung den Code 0x8 und den Anfangswert 0. Erst wenn der Client den Wert 1 empfangen hat, darf er erweitertes CONNECT auf neuen Streams verwenden. Sendet er den zusätzlichen Pseudo-Header vorher, sieht ein Server ohne Erweiterung eine fehlerhafte Anfrage. Die Zustimmung ist die Bedingung dafür, die Bedeutung des Verbs zu ändern.

Nach dieser Freigabe öffnet der Client einen Stream mit :method = CONNECT und :protocol = websocket. Er ergänzt :scheme, :path und :authority der Ziel-URI. Gerade das letzte Feld kann täuschen. Beim gewöhnlichen CONNECT benennt :authority den Host, zu dem ein Tunnel aufgebaut wird. Beim erweiterten CONNECT ist es die Authority der Ziel-URI. RFC 8441 untersagt dem Server, allein wegen CONNECT einen herkömmlichen Tunnel zu diesem Host aufzubauen. :protocol bezeichnet das Protokoll, das der neue Stream tragen soll.

Für eine sichere WebSocket-URI steht https im Zielschema, für eine ungesicherte http. Pfad und Authority behalten ihre Rolle als Adresse des Dienstes. Bei einem HTTP/2-Forward-Proxy ist der Ablauf anders: Der Client soll zunächst gewöhnliches CONNECT bis zum WebSocket-Server verwenden. Die HTTP-Version innerhalb dieses Tunnels bestimmt danach den WebSocket-Start. Proxy-Tunnel und erweiterter Stream zum Ursprungsserver sind unterschiedliche Abmachungen.

Auf den 200-Status folgen die Frames

Erweitertes CONNECT ersetzt den GET-Start. Es sendet weder Connection noch Upgrade; auch die HTTP/1.1-Verarbeitung von Sec-WebSocket-Key und Sec-WebSocket-Accept entfällt auf diesem Weg. :protocol übernimmt deren Aufgabe. Origin, WebSocket-Version, Unterprotokolle und Erweiterungen bleiben nach den WebSocket-Regeln erhalten. Die Zulassung zum Kanal ändert sich, nicht die Frames nach der Zulassung.

Das Beispiel in RFC 8441 zeigt die Server-Einstellung, die CONNECT-Anfrage und eine Antwort :status = 200. Danach transportieren HTTP/2-DATA-Frames WebSocket-Daten in beide Richtungen. Der Stream übernimmt die Rolle, die in RFC 6455 die ganze TCP-Verbindung hatte. Priorisierung, Abbruch und Flusskontrolle bleiben HTTP/2-Funktionen; END_STREAM und RST_STREAM beenden genau diesen Kanal regulär oder ausnahmsweise. Andere Streams können währenddessen weiterlaufen.

Ein Chat darf also lange offen bleiben, ohne den Bildabruf festzuhalten. Der Server kann die Erweiterung ablehnen, indem er die Einstellung nicht aktiviert. Der Client kann das erkennen, bevor er seine besondere Anfrage stellt. Freigabe und Verwendung sind auf dem Draht sichtbar; niemand muss einen alten 101-Wechsel in einen gemeinsamen Transport hineininterpretieren.

Die anderen Mieter behielten die Verbindung

RFC 8441 entschied sich für einen begrenzten Eingriff. Ein tieferer Umbau wäre denkbar, doch erweitertes CONNECT löste das unmittelbare Nebeneinander von WebSocket und HTTP/2. Nach dem Start gelten WebSocket-Framing und die meisten Sicherheitserwägungen aus RFC 6455 weiter. Die Maskierung dieser Frames ist eine andere Geschichte; hier geht es um das Recht, den tragenden Stream zu öffnen.

Die vier amtlichen Quellen belegen Mechanismus und registrierte Einstellung. Für die Nutzung durch einen bestimmten Dienst bräuchte man datierte Client-, Server- und Proxy-Versionen sowie aufgezeichnete SETTINGS- und HEADERS-Nachrichten. Der historische Beschluss steht bereits in der Norm: HTTP/2 gab keine gemeinsame Verbindung an eine einzelne Unterhaltung ab. WebSocket erhielt einen ausgehandelten Platz darin.