Lær ditt Go-program å snakke som Chrome

Hvis du noen gang har reist utenlands og bestilt kaffe med en setning fra læreboken, kjenner du blikket baristaen gir deg. Grammatikken din er i orden. Hvert ord finnes i ordboken. Likevel vet alle i kafeen, innen et halvt sekund, at du er fra andre kanter.
Go sin standard HTTP-klient har litt av det samme problemet. Den er et utmerket standardvalg: pålitelig, ryddig og klar for seriøst arbeid rett ut av esken. Når programmet ditt tar kontakt med en server, ser det imidlertid utvetydig ut som et Go-program. For det meste bryr ingen seg om det. Likevel finnes det nettsteder, CDN-er og testoppsett som er nøye med hvem som banker på døren, og de oppfører seg ganske forskjellig avhengig av hvilken type klient de tror de snakker med.
Derfor bygde vi gosuda.org/chromenet. I stedet for å trene Go sin standardklient til å etterligne en nettleser på en akseptabel måte, lar chromenet et Go-program kommunisere med nettet gjennom samme nettverksmotor som Google Chrome bruker, nemlig Chromiums egen nettverkskode. Enten du vil sjekke hvordan testoppsettene dine behandler nettlesertrafikk, eller snakke med et nettsted bak en kresen CDN, fjerner det å kommunisere gjennom Chrome-motoren et helt lag med gjetting.
Du trenger ikke skrive om applikasjonen din for å bruke det. I koden din fungerer det som en drop-in-erstatning for http.Transport. Du fortsetter å bruke http.Client slik du alltid har gjort, og chromenet tar seg av samtalen under overflaten.
For å prøve den nyeste utgivelsen, installer den med go get:
1go get gosuda.org/chromenet@v0.2.10157081033800
Gi deretter transporten til klienten din:
1client := http.Client{
2 Transport: chromenet.NewTransport(chromenet.Options{}),
3}
Med denne utgivelsen går hele spekteret av moderne webtrafikk gjennom Chrome-motoren. Den dekker nå vanlige webforespørsler, WebSocket og WebTransport. Tidligere versjoner håndterte bare vanlige forespørsler ordentlig, mens WebSocket og WebTransport bare var erstatninger. Det betydde at den første hilsenen ved inngangsdøren hørtes ut som Chrome, men hvis du byttet til en annen type samtale, kunne dekket ditt falle. Denne utgivelsen erstatter disse midlertidige løsningene med den ekte varen.
Vent litt, hvis vi bruker Chromiums egen nettverkskode, betyr det at det stille Go-bygget ditt blir til en omfattende hodepine med C-kompilatoren? Heldigvis nei. Go-koden din forblir ren Go, uten cgo og uten behov for en C-kompilator.
I stedet for å sveise nettleserkode direkte inn i det kjørbare programmet ditt, kjører chromenet motoren som et lite, eget program ved siden av Go-programmet ditt. Tenk på det som å leie en flytende lokal tolk som går ved din side, i stedet for å forsøke å bygge om stemmebåndene dine. Fordi motoren kjører i det separate programmet, kan et krasj der ikke ta tjenesten din ned.

Go-programmet ditt forblir ren Go, mens et lite følgeprogram sender trafikken gjennom Chromiums nettverksmotor.
Det er heller ikke noe ekstra å installere på arbeidsstasjonen eller serverne dine. Motorbinærfilene for Linux, macOS og Windows, både for Intel/AMD og ARM, leveres direkte inne i Go-modulen og verifiseres før de kjøres.
Å levere binærfiler inne i en modul reiser forståelig nok et spørsmål for alle som bryr seg om tillit, og vi ønsket et enkelt svar. Binærfilene bygges på en reproduserbar måte fra en bestemt Chromium-utgivelse, for tiden Chromium 157, slik at alle kan bygge dem på nytt og få nøyaktig de samme bytene, og hver utgivelse attesteres av GitHub. For å holde tritt med nettleserverdenen uten manuelt arbeid, følger en planlagt jobb Chromiums stabile kanal og oppdaterer versjonen automatisk når en ny Chrome lanseres.
Hva med uTLS?
Hvis du har prøvd å få en Go-klient til å se ut som en nettleser tidligere, har du sannsynligvis møtt uTLS. Det er et vakkert stykke arbeid: et Go-bibliotek som lar deg kle den aller første meldingen i en sikker forbindelse slik at den ligner Chrome, Firefox eller hva du måtte ønske. Det er lite, det er rent Go, og ingenting ekstra kjører ved siden av programmet ditt.
Haken er hvor langt kostymet rekker. uTLS dekker håndtrykket, altså de første ordene i samtalen. Alt etter det må du fortsatt bygge selv: HTTP/2-laget må kobles opp og finjusteres for hånd, HTTP/3 er et eget eventyr, og WebSocket eller WebTransport krever enda mer lim. Chrome-forhåndsinnstillingene er også kopier, så noen må holde dem oppdatert hver gang Chrome endrer vaner. Det er litt som å tilpasse aksenten til en person mens resten av kroppsspråket fortsatt avslører dem.
chromenet tar den motsatte veien. Den etterligner ikke Chrome, den ber Chromes egen motor om å stå for samtalen, slik at håndtrykket, måten forbindelser gjenbrukes på, protokolloppgraderingene og transportene alle kommer fra ett sted og beveger seg sammen når Chromium beveger seg.
Avveiningen er ærlig. uTLS er lettere og lar deg utforme enhver hilsen du kan tenke deg, mens chromenet medfører en hjelper på 25 MB og gir deg Chromes oppførsel i stedet for en egendefinert en. Hvis du ønsker en liten avhengighet og full kontroll over håndtrykket, er uTLS fortsatt et utmerket valg.
Ethvert design har avveininger, og vi ønsker å være åpne om begrensningene her. Å pakke inn en ekte nettleser-nettverksmotor er ikke lite: hver motorbinærfil er omtrent 25 MB. På macOS er ikke binærfilene notarisert. Og på Linux må systemet ditt ha glibc 2.31 eller nyere. Hvis disse grensene passer for oppsettet ditt, får du ekte Chrome-nettverking ved å bytte ut ett enkelt transportfelt.
Prosjektet finnes på github.com/gosuda/chromenet. Hvis du kjenner søsterprosjektene i open source-familien til gosuda, gosuda.org/hqq og gosuda.org/sqlite3, vil ånden føles kjent: å ta dyktig, tung maskineri fra den bredere programvareverdenen og gjøre det hjemme i ren Go.
Så, hvis du griper etter uTLS fordi Go-programmet ditt må høres ut som en nettleser, bør du prøve chromenet. Det kan være et godt alternativ til uTLS, særlig når du trenger mer enn HTTPS-forespørsler: HTTP/2, HTTP/3, WebSocket og WebTransport går alle gjennom samme Chrome-motor, uten limkode på din side.