---
id: 6e0bce9e22a4bf7d9672c59e67bcf5ec
author: Lemon Mint
title: 'gosuda.org/chromenet: Síťový zásobník Chromia pro Go, sestavený reprodukovatelným způsobem z pevně zafixovaného vydání'
description: CGO_ENABLED=0 Go http.RoundTripper, který odesílá požadavky přes vlastní síťový zásobník Chromium //net (HTTP/1.1, HTTP/2, QUIC/HTTP/3, BoringSSL) v izolovaném HQQ workeru, se zdrojovým kódem, toolchainy a šesti vloženými binárními soubory připnutými pomocí SHA-256 a sestavenými v gvx sandboxech.
language: cs
date: 2026-11-09T00:00:00Z
path: /chromenet
go_package: gosuda.org/chromenet
go_repourl: https://github.com/gosuda/chromenet.git
category: network
---

`gosuda.org/chromenet` je Go `http.RoundTripper`, který odesílá požadavky přes vlastní síťový zásobník Chromium. Tím zásobníkem je `//net` z oficiálního vydání Chromium: jeho implementace HTTP/1.1, HTTP/2 a QUIC/HTTP/3, BoringSSL, konfigurace TLS prohlížeče Chrome a Chrome Root Store. Běží v samostatném pracovním procesu `chrome_net_server`, zatímco část v Go zůstává čistě v Go (`CGO_ENABLED=0`) a s pracovním procesem komunikuje přes [HQQ](https://gosuda.org/hqq) shared-memory RPC.

```bash
go get gosuda.org/chromenet@v0.1.10157081033800
```

## Proč spouštět síťový zásobník Chromium

Program v Go, který komunikuje s webem pomocí `net/http`, se vůči serveru prezentuje jako klient v Go. To je správný výchozí přístup pro komunikaci mezi službami. Je však nevhodný tam, kde chování serveru závisí na tom, za jaký typ klienta server klienta považuje: endpointy vyžadující prohlížeč, anti-bot middleware, CDN, které různým TLS a HTTP/2 otiskům posílají různé verze protokolů, a testy, které musejí reprodukovat to, co zažívá skutečný prohlížeč.

Standardní knihovna Go nemůže poskytnout drátové chování prohlížeče. `crypto/tls` má vlastní pořadí cipher suites a sadu rozšíření a `net/http` má vlastní nastavení HTTP/2. Knihovny, které napodobují prohlížeč kopírováním bajtů jeho ClientHello, je musejí kopírovat znovu při každém vydání. `chromenet` jde opačnou cestou: nenapodobuje síťový zásobník Chromium, ale přímo jej spouští.

Měřeno na enginu `darwin/arm64` proti veřejné službě pro fingerprinting (`tls.peet.ws`) výchozí konfigurace hlásí následující hodnoty:

| Vlastnost                          | Naměřená hodnota                                                      |
| :--------------------------------- | :-------------------------------------------------------------------- |
| Vyjednaný protokol                 | `h2`                                                                  |
| JA4                                | `t13d1516h2_8daaf6152771_806a8c22fdea`                                |
| HTTP/2 fingerprint (formát Akamai) | `1:65536;2:0;4:6291456;6:262144\|15663105\|0\|m,a,s,p`                |
| User-Agent                         | desktopový Chrome s hlavní verzí enginu, např. `Chrome/157.0.0.0`     |

S `ForceHTTP3` byly požadavky na `cloudflare-quic.com` a `www.google.com` zodpovězeny přes HTTP/3. Tyto hodnoty pochází z jedné platformy a z jednoho dne. Engine je samotný zásobník, takže se hodnoty změní, když se změní připnuté vydání Chromium.

## Použití

`NewTransport` vrací `http.RoundTripper`. Používejte jej všude, kde byste použili `http.Transport`:

```go
package main

import (
	"fmt"
	"io"
	"net/http"

	"gosuda.org/chromenet"
)

func main() {
	client := &http.Client{Transport: chromenet.NewTransport(chromenet.Options{})}

	resp, err := client.Get("https://example.com/")
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Println(resp.Proto, resp.StatusCode, len(body))
}
```

Při prvním požadavku modul zapíše vloženou binárku pracovního procesu pro vaši platformu do uživatelského cache adresáře, ověří její SHA-256 digest pomocí `gosuda.org/hqq/secureexec`, spustí ji s rodičovskou smyčkou života (`--parent-stdin`, takže skončí, když skončí váš proces) a otevře session pool. Nic není třeba instalovat.

Některé vlastnosti odpovídají `http.Transport`, aby `http.Client` fungoval beze změn:

- Transport nesleduje přesměrování a neukládá cookies. `http.Client` obojí dělá stejně jako u `http.Transport`.
- Odpovědi komprimované pomocí gzip, deflate, Brotli nebo zstd přicházejí dekódované a `resp.Uncompressed` je true.
- Požadavek drží jednu session enginu, dokud není uzavřeno tělo odpovědi. Těla zavírejte.
- Zrušení kontextu požadavku zruší požadavek uvnitř Chromium.
- Síťová selhání jsou hodnoty `*client.NetError` nesoucí kód a název chyby Chromium:

```go
var ne *client.NetError
if errors.As(err, &ne) {
	fmt.Println(ne.Code, ne.Name) // -105 ERR_NAME_NOT_RESOLVED
}
```

### Možnosti

| Pole                          | Účinek                                                                                                    |
| :---------------------------- | :-------------------------------------------------------------------------------------------------------- |
| `UserAgent`                   | Nahradí výchozí User-Agent Chrome. Hlavička `User-Agent` v požadavku má stále přednost.                   |
| `AcceptLanguage`              | Nahradí `en-US,en;q=0.9`.                                                                                 |
| `Proxy`                       | Pravidla proxy Chromium, např. `http://127.0.0.1:8080` nebo `socks5://127.0.0.1:1080`. Prázdná hodnota znamená přímé připojení. |
| `DisableHTTP2`, `DisableQUIC` | Vypnou příslušné protokoly.                                                                               |
| `ForceHTTP3`                  | Použije QUIC pro každý origin bez čekání na oznámení `Alt-Svc`.                                           |
| `InsecureSkipVerify`          | Přijme libovolný certifikát serveru.                                                                      |
| `Pool`                        | Session enginu k použití. Nil použije `client.DefaultPool()`, který povoluje 64 souběžných požadavků.     |

Transporty se shodnými možnostmi sdílejí jeden Chromium `URLRequestContext`, takže connection pooly, HTTP/2 sessions a QUIC sessions se znovu používají napříč požadavky. Nastavení `HQQ_CHROME_NET_SERVER=/path/to/chrome_net_server` nahradí vloženého pracovního procesu, například lokálním buildem.

## Jak to funguje

| Vrstva              | Co zde běží                                                                                                                                                                       |
| :------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Váš program         | `http.Client` a `chromenet.Transport`, čistě v Go.                                                                                                                               |
| Hranice procesu     | HQQ shared-memory RPC. Rozhraní je `chrome_net.idl`, které `hqq-bindgen` zkompiluje do klienta v Go a do C serverového glue kódu.                                              |
| `chrome_net_server` | Malá vrstva v C++ nad Chromium: jedno síťové vlákno, které vlastní všechny objekty `//net`, a session vlákna, která blokují na požadavku, dokud jim síťové vlákno neodpoví.       |
| Chromium `//net`    | `URLRequestContext`, `URLRequest`, HTTP/2 a QUIC sessions, BoringSSL.                                                                                                            |

IDL má šest operací, na kterých záleží: vytvořit engine z možností ve tvaru `key=value`, zahájit požadavek jeho hlavičkou (`METHOD URL` plus řádky hlaviček) a délkou těla, zapisovat části těla požadavku, čekat na hlavičku odpovědi, číst dekódované tělo a zrušit handly. Handle požadavku deklaruje `@cancel`, takže opuštěné volání přeruší požadavek uvnitř Chromium a nenechá jej běžet až do konce.

Izolace zásobníku v pracovním procesu je stejně tak bezpečnostní vlastností jako otázkou balení. Síťový kód Chromium zpracovává nedůvěryhodný vstup z otevřeného internetu. Pokud spadne, nespadne s ním i vaše služba v Go: volání skončí chybou, session se zahodí a klient při příští potřebě spustí nový pracovní proces.

## Reprodukovatelně sestaveno, připnuto pomocí SHA-256

Binárka o velikosti 25 MB, která obsahuje Chromium, je důvěryhodná pouze tehdy, pokud lze přesně říci, co do ní vstoupilo. `chromenet` sleduje stabilní vydání Chromium stejným způsobem, jakým `gosuda.org/sqlite3` sleduje SQLite: zdrojový kód se nikdy nevendoruje, pouze se připíná.

| Připnutí                                                                                                                                  | Kde                            |
| :---------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------- |
| Vydání Chromium a jeho oficiální archiv zdrojového kódu `-lite`                                                                           | `third_party/chromium/VERSION` |
| SHA-256 archivu a každého toolchainu, který vydání připíná: clang, Rust, GN, ninja, runtime clang pro Windows, xwin                       | `third_party/chromium/SHA256`  |
| Verze MSVC CRT a Windows SDK stahované přes xwin                                                                                          | `third_party/chromium/WINSDK`  |
| Vydání sandbox runtime (`rungv`), digest guest image, datum snapshotu Debianu                                                             | `scripts/engine/BUILDENV`      |
| C runtime HQQ                                                                                                                             | `go.mod` a `go.sum`            |

Aktuálním připnutím je Chromium `157.0.8103.38`. Stažení, které neodpovídá svému připnutí, build zastaví. Vydání aplikuje na Chromium přesně jednu záplatu: na Linuxu se `chrome_net_server` sestavuje bez NSS a ověřuje certifikáty serverů pouze proti Chrome Root Store, takže binárka nepotřebuje nic nad rámec libc.

Linuxové a Windows enginy se sestavují uvnitř sandboxů [gvx](https://gosuda.org/blog/posts/gvx-cross-platform-linux-containers-z48916d01): neprivilegovaných procesů s připnutým guest image a bez hostitelského démona. Windows enginy se křížově kompilují na Linuxu pomocí clang-cl a lld-link z Chromium proti Windows SDK, které xwin stahuje od Microsoftu. Enginy pro macOS se sestavují nativně na macOS runneru, protože build Chromia pro macOS vyžaduje Xcode.

Opětovné sestavení stejného commitu dalo bajtově identické binárky napříč samostatnými CI běhy. Vydané binárky jsou bajtově identické s těmi, které předchozí CI běh sestavil pro commit, jímž byl engine začleněn do monorepa, na všech šesti platformách.

| Platforma       | Velikost binárky |
| :-------------- | ---------------: |
| `linux/amd64`   |          27,9 MB |
| `linux/arm64`   |          27,4 MB |
| `darwin/amd64`  |          26,2 MB |
| `darwin/arm64`  |          23,9 MB |
| `windows/amd64` |          27,3 MB |
| `windows/arm64` |          25,8 MB |

Linuxové enginy závisí pouze na `libc`, `libm`, `libdl`, `libpthread` a `libgcc_s` a vyžadují glibc 2.31 nebo novější.

### Sledování Chromium a vydání

Naplánovaný workflow kontroluje stabilní vydání Chromium každých šest hodin. Pro nové vydání přepíše připnutí, sestaví a otestuje všech šest enginů ve větvi `chromium/<version>`, attestuje binárky a commitne připnutí společně s vloženými binárkami, jejich digesty a texty licencí do `main` jedním commitem. V monorepu soubory `OWNERS` přesně těmto souborům udělují bota workflow, takže aktualizace projde bez lidského kroku, zatímco změny samotného návodu na sestavení (připnutí Windows SDK a záplata) stále vyžadují vlastníka.

Každá vydaná binárka nese attestaci původu sestavení od workflow, které ji vytvořilo:

```bash
gh attestation verify chrome_net_server_linux_amd64 --repo gosuda/chromenet
```

Texty licencí toho, co každá binárka obsahuje (Chromium, BoringSSL, QUICHE a zbytek celého build grafu), generuje vlastní nástroj Chromium `tools/licenses/licenses.py` a jsou vydávány spolu s binárkou jako `NOTICE_<os>_<arch>.txt`.

## Omezení

- `DialWebSocket` je čistě Go klient podle RFC 6455 a nepoužívá zásobník Chromium.
- `DialWebTransport` je implementace běžící v rámci procesu. Na server nedosáhne.
- Výchozí JA4 a HTTP/2 fingerprinty jsou fingerprinty připnutého vydání Chromium. Chromium je mezi vydáními mění a `chromenet` je sleduje.
- Binárky pro macOS jsou podepsány ad-hoc a nejsou notarizovány.
- Pracovní proces stojí paměť. Každá binárka enginu má na disku 24 až 28 MB a runtime Chromium spouští thread pool a síťové vlákno.
- Session enginu je držena, dokud není uzavřeno tělo odpovědi. Program, který těla odpovědí neuzavírá, vyčerpá pool.

## Zdroj

Repozitář je [github.com/gosuda/chromenet](https://github.com/gosuda/chromenet), zrcadlený z `//net/chromenet` v monorepu gosuda. Build návod se nachází v `scripts/engine`, glue kód enginu v `engine/` a rozhraní v `chrome_net.idl`.
