GoSuda

Wie Sie Ihr Go-Programm beibringen, wie Chrome zu sprechen

By Lemon Mint views ...

Wenn Sie jemals im Ausland unterwegs waren und einen Kaffee mit einer lehrbuchhaft perfekten Wendung bestellt haben, kennen Sie den Blick, den Ihnen der Barista zuwirft. Ihre Grammatik ist in Ordnung. Jedes Wort steht im Wörterbuch. Und doch weiß innerhalb einer halben Sekunde jeder im Café, dass Sie von auswärts kommen.

Go's Standard-HTTP-Client hat ein wenig von diesem Problem. Er ist ein hervorragender Standard: zuverlässig, sauber und sofort einsatzbereit für ernsthafte Arbeit. Wenn Ihr Programm jedoch einen Server kontaktiert, sieht es unverkennbar wie ein Go-Programm aus. Meistens stört das niemanden. Dennoch achten manche Websites, CDNs und Testumgebungen genau darauf, wer an die Tür klopft, und sie verhalten sich deutlich unterschiedlich, je nachdem, für welche Art von Client sie den Gesprächspartner halten.

Deshalb haben wir gosuda.org/chromenet entwickelt. Anstatt den Standard-Client von Go dazu zu bringen, eine halbwegs überzeugende Browser-Imitation zu liefern, erlaubt chromenet einem Go-Programm, mit dem Web über dieselbe Netzwerk-Engine zu kommunizieren, die Google Chrome verwendet, nämlich den eigenen Netzwerkcode von Chromium. Ob Sie prüfen möchten, wie Ihre eigenen Testumgebungen Browser-Datenverkehr behandeln, oder mit einer Website hinter einem anspruchsvollen CDN sprechen wollen: Die Kommunikation über die Engine von Chrome beseitigt eine ganze Schicht an Ungewissheit.

Sie müssen Ihre Anwendung nicht umschreiben, um es zu verwenden. In Ihrem Code funktioniert es als Drop-in-Ersatz für http.Transport. Sie verwenden http.Client weiterhin wie gewohnt, und chromenet übernimmt die Kommunikation im Hintergrund.

Um die neueste Version auszuprobieren, installieren Sie sie mit go get:

1go get gosuda.org/chromenet@v0.2.10157081033800

Übergeben Sie anschließend dessen Transport an Ihren Client:

1client := http.Client{
2	Transport: chromenet.NewTransport(chromenet.Options{}),
3}

Mit dieser Version läuft das gesamte Spektrum des modernen Web-Datenverkehrs über die Engine von Chrome. Sie umfasst nun gewöhnliche Web-Anfragen, WebSocket und WebTransport. Frühere Versionen behandelten nur gewöhnliche Anfragen richtig, während WebSocket und WebTransport lediglich Platzhalter waren. Das bedeutete, dass Ihre anfängliche Begrüßung an der Tür nach Chrome klang, aber wenn Sie zu einer anderen Gesprächsform wechselten, konnte Ihre Tarnung auffliegen. Diese Version ersetzt diese Platzhalter durch die echte Lösung.

Moment, wenn wir den eigenen Netzwerkcode von Chromium verwenden, bedeutet das dann, dass aus Ihrem schlichten Go-Build ein ausuferndes Kopfzerbrechen mit einem C-Compiler wird? Glücklicherweise nein. Ihr Go-Code bleibt reines Go, ohne cgo und ohne dass ein C-Compiler benötigt wird.

Anstatt den Browser-Code direkt in Ihre Binärdatei einzubauen, betreibt chromenet die Engine als kleines, separates Programm neben Ihrem Go-Programm. Stellen Sie sich das vor wie einen fließend sprechenden einheimischen Dolmetscher, der an Ihrer Seite geht, anstatt zu versuchen, Ihre eigenen Stimmbänder nachzubauen. Da die Engine in diesem separaten Programm läuft, kann ein Absturz darin Ihren Dienst nicht zum Erliegen bringen.

So funktioniert chromenet: Ihr Go-Programm fragt ein kleines Begleitprogramm, das die Netzwerk-Engine von Chromium betreibt und mit dem Web kommuniziert

Ihr Go-Programm bleibt reines Go, während ein kleines Begleitprogramm den Datenverkehr über die Netzwerk-Engine von Chromium leitet.

Auch auf Ihrem Arbeitsplatzrechner oder Ihren Servern muss nichts zusätzlich installiert werden. Die Engine-Binärdateien für Linux, macOS und Windows, sowohl für Intel/AMD als auch für ARM, werden direkt im Go-Modul ausgeliefert und vor ihrer Ausführung verifiziert.

Binärdateien in einem Modul auszuliefern wirft verständlicherweise eine Frage für jeden auf, dem Vertrauen wichtig ist, und wir wollten eine unkomplizierte Antwort geben. Die Binärdateien werden auf reproduzierbare Weise aus einer bestimmten Chromium-Version erstellt, derzeit Chromium 157, sodass jeder sie neu bauen und exakt dieselben Bytes erhalten kann. Zudem wird jede Version von GitHub attestiert. Um mit der Browserwelt Schritt zu halten, ohne manuelle Routinearbeiten, verfolgt ein geplanter Job den stabilen Kanal von Chromium und aktualisiert die Version automatisch, sobald ein neues Chrome erscheint.

Was ist mit uTLS?

Wenn Sie schon einmal versucht haben, einen Go-Client wie einen Browser aussehen zu lassen, sind Sie wahrscheinlich uTLS begegnet. Es ist ein schönes Stück Arbeit: eine Go-Bibliothek, mit der Sie die allerersten Nachricht einer gesicherten Verbindung so gestalten können, dass sie Chrome, Firefox oder jedem anderen gewünschten Client ähnelt. Sie ist klein, sie ist reines Go, und neben Ihrem Programm läuft nichts Zusätzliches.

Der Haken liegt darin, wie weit das Kostüm reicht. uTLS deckt den Handshake ab, also die ersten Worte des Gesprächs. Alles Weitere müssen Sie selbst aufbauen: Die HTTP/2-Schicht muss von Hand eingerichtet und abgestimmt werden, HTTP/3 ist ein eigenes Abenteuer, und WebSocket oder WebTransport erfordern noch mehr Verbindungsarbeit. Die Chrome-Voreinstellungen sind zudem Kopien, sodass jemand sie jedes Mal aktuell halten muss, wenn Chrome seine Gewohnheiten ändert. Es ähnelt ein wenig dem Nachahmen des Akzents einer Person, während ihre übrige Körpersprache sie dennoch verrät.

chromenet geht den gegenteiligen Weg. Es imitiert Chrome nicht, sondern lässt die eigene Engine von Chrome die Kommunikation übernehmen, sodass Handshake, Wiederverwendung von Verbindungen, Protokollwechsel und Transporte aus einer Quelle stammen und sich gemeinsam weiterentwickeln, wenn sich Chromium weiterentwickelt.

Der Kompromiss ist ehrlich. uTLS ist leichtgewichtiger und erlaubt es Ihnen, jede beliebige Begrüßung zu gestalten, die Sie sich vorstellen können, während chromenet einen 25 MB großen Helfer mitbringt und Ihnen das Verhalten von Chrome statt eines eigenen Verhaltens bietet. Wenn Sie eine winzige Abhängigkeit und vollständige Kontrolle über den Handshake wünschen, ist uTLS nach wie vor eine ausgezeichnete Wahl.

Jedes Design hat Abwägungen, und wir möchten die Grenzen hier offen benennen. Eine echte Browser-Netzwerk-Engine einzubinden ist nicht klein: Jede Engine-Binärdatei umfasst etwa 25 MB. Unter macOS sind die Binärdateien nicht notarisiert. Und unter Linux benötigt Ihr System glibc 2.31 oder neuer. Wenn diese Grenzen zu Ihrer Umgebung passen, erhalten Sie echte Chrome-Netzwerkfunktionen durch den Austausch eines einzigen Transportfelds.

Das Projekt befindet sich unter github.com/gosuda/chromenet. Wenn Sie dessen Schwesterprojekte in der Open-Source-Familie von gosuda kennen, gosuda.org/hqq und gosuda.org/sqlite3, wird Ihnen der Geist vertraut vorkommen: leistungsfähige, schwere Technik aus der breiteren Softwarewelt zu übernehmen und sie in reinem Go heimisch wirken zu lassen.

Wenn Sie also zu uTLS greifen, weil Ihr Go-Programm wie ein Browser klingen soll, probieren Sie chromenet aus. Es kann eine gute Alternative zu uTLS sein, besonders wenn Sie mehr als HTTPS-Anfragen benötigen: HTTP/2, HTTP/3, WebSocket und WebTransport laufen alle über dieselbe Chrome-Engine, ohne Glue-Code auf Ihrer Seite.