---
id: 6e0bce9e22a4bf7d9672c59e67bcf5ec
author: Lemon Mint
title: 'gosuda.org/chromenet: Pinned Bir Sürümden Yeniden Üretilebilir Biçimde Oluşturulmuş, Go için Chromium Ağ Yığını'
description: CGO_ENABLED=0 Go http.RoundTripper, isolated bir HQQ worker içinde, Chromium'un kendi //net yığını (HTTP/1.1, HTTP/2, QUIC/HTTP/3, BoringSSL) üzerinden istekleri gönderir; kaynak kodu, toolchain'ler ve SHA-256 ile sabitlenmiş, gvx sandbox'larında derlenmiş altı gömülü binary ile birlikte sunulur.
language: tr
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`, Chromium'un kendi ağ yığını üzerinden istekleri gönderen bir Go `http.RoundTripper` uygulamasıdır. Yığın, resmi bir Chromium sürümünden alınan `//net` bileşenidir: HTTP/1.1, HTTP/2 ve QUIC/HTTP/3 uygulamaları, BoringSSL, Chrome'un TLS yapılandırması ve Chrome Root Store. Ayrı bir worker süreci olan `chrome_net_server` içinde çalışır; Go tarafı saf Go olarak kalır (`CGO_ENABLED=0`) ve worker ile [HQQ](https://gosuda.org/hqq) paylaşımlı bellek RPC'si üzerinden haberleşir.

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

## Neden Chromium'un Ağ Yığınını Çalıştırmalı

`net/http` ile web'e erişen bir Go programı, sunucuya kendisini bir Go istemcisi olarak tanıtır. Bu, servisler arası trafik için doğru varsayılandır. Ancak sunucunun davranışı, karşısındaki istemcinin türüne bağlı olduğunda yanlış bir seçimdir: tarayıcı kontrollü uç noktalar, bot karşıtı ara katmanlar, farklı TLS ve HTTP/2 parmak izlerine farklı protokol sürümleri sunan CDN'ler ve gerçek bir tarayıcının deneyimini birebir yeniden üretmesi gereken testler bu kapsamdadır.

Go standart kütüphanesi, bir tarayıcının ağ düzeyindeki davranışını taklit edemez. `crypto/tls` kendi cipher-suite sıralamasına ve extension kümesine sahiptir, `net/http` ise kendi HTTP/2 ayarlarını kullanır. Bir tarayıcıyı, ClientHello baytlarını kopyalayarak taklit eden kütüphaneler ise her sürümde kopyalamaya devam etmek zorunda kalır. `chromenet` ise farklı bir yol izler: Chromium ağ yığınını taklit etmez, doğrudan çalıştırır.

`darwin/arm64` motorunda, herkese açık bir parmak izi servisine (`tls.peet.ws`) karşı yapılan ölçümlerde varsayılan yapılandırma şu sonuçları verir:

| Özellik                               | Gözlemlenen değer                                                     |
| :------------------------------------ | :-------------------------------------------------------------------- |
| Müzakere edilen protokol              | `h2`                                                                  |
| JA4                                   | `t13d1516h2_8daaf6152771_806a8c22fdea`                                |
| HTTP/2 parmak izi (Akamai biçimi)     | `1:65536;2:0;4:6291456;6:262144\|15663105\|0\|m,a,s,p`                |
| User-Agent                            | Motorun ana sürümüne ait masaüstü Chrome, örneğin `Chrome/157.0.0.0`  |

`ForceHTTP3` etkinleştirildiğinde, `cloudflare-quic.com` ve `www.google.com` adreslerine yapılan istekler HTTP/3 üzerinden yanıtlandı. Bu sayılar tek bir platformdan, tek bir günde elde edilmiştir. Motor, yığının kendisi olduğundan, sabitlenmiş Chromium sürümü değiştiğinde bu sayılar da değişir.

## Kullanım

`NewTransport`, bir `http.RoundTripper` döndürür. `http.Transport` kullanabileceğiniz her yerde bunu kullanabilirsiniz:

```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))
}
```

İlk istekte modül, gömülü worker ikilisini platformunuz için kullanıcı önbellek dizinine yazar, SHA-256 özetini `gosuda.org/hqq/secureexec` ile doğrular, onu bir üst süreç yaşam bağıyla (`--parent-stdin`, böylece programınız sonlandığında worker da sonlanır) başlatır ve bir oturum havuzu açar. Herhangi bir şeyin kurulması gerekmez.

`http.Client`'ın değiştirilmeden çalışabilmesi için bazı davranışlar `http.Transport` ile aynıdır:

- Transport yönlendirmeleri takip etmez ve çerez saklamaz. `http.Client` ise `http.Transport` ile olduğu gibi bunların ikisini de yapar.
- gzip, deflate, Brotli veya zstd ile sıkıştırılmış yanıtlar çözülmüş olarak gelir ve `resp.Uncompressed` değeri true olur.
- Bir istek, yanıt gövdesi kapatılana kadar bir motor oturumunu tutar. Gövdeleri kapatın.
- İstek bağlamını iptal etmek, Chromium içindeki isteği de iptal eder.
- Ağ hataları, Chromium hata kodunu ve adını taşıyan `*client.NetError` değerleridir:

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

### Seçenekler

| Alan                          | Etki                                                                                                       |
| :---------------------------- | :--------------------------------------------------------------------------------------------------------- |
| `UserAgent`                   | Varsayılan Chrome User-Agent değerini değiştirir. İstek başlığındaki `User-Agent` yine de öncelikli olur.  |
| `AcceptLanguage`              | `en-US,en;q=0.9` değerini değiştirir.                                                                      |
| `Proxy`                       | `http://127.0.0.1:8080` veya `socks5://127.0.0.1:1080` gibi Chromium proxy kuralları. Boş bırakılırsa doğrudan bağlanır. |
| `DisableHTTP2`, `DisableQUIC` | Bu protokolleri kapatır.                                                                                   |
| `ForceHTTP3`                  | `Alt-Svc` duyurusunu beklemeden her origin için QUIC kullanır.                                             |
| `InsecureSkipVerify`          | Herhangi bir sunucu sertifikasını kabul eder.                                                              |
| `Pool`                        | Kullanılacak motor oturumları. Nil ise, eşzamanlı 64 isteğe izin veren `client.DefaultPool()` kullanılır.  |

Eşit seçeneklere sahip transport'lar tek bir Chromium `URLRequestContext` paylaşır; bu nedenle bağlantı havuzları, HTTP/2 oturumları ve QUIC oturumları istekler arasında yeniden kullanılır. `HQQ_CHROME_NET_SERVER=/path/to/chrome_net_server` ayarlandığında gömülü worker yerine belirtilen ikili kullanılır; örneğin yerel bir derleme için.

## Nasıl Çalışır

| Katman              | Burada çalışan                                                                                                                                                                              |
| :------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Programınız         | `http.Client` ve `chromenet.Transport`, saf Go.                                                                                                                                            |
| Süreç sınırı        | HQQ paylaşımlı bellek RPC'si. Arayüz `chrome_net.idl` dosyasıdır ve `hqq-bindgen` tarafından Go istemcisine ve C sunucu katmanına derlenir.                                               |
| `chrome_net_server` | Chromium üzerinde küçük bir C++ katmanı: her `//net` nesnesine sahip tek bir ağ iş parçacığı ve yanıt gelene kadar bir isteği bekleyen oturum iş parçacıkları.                             |
| Chromium `//net`    | `URLRequestContext`, `URLRequest`, HTTP/2 ve QUIC oturumları, BoringSSL.                                                                                                                   |

IDL'de önemli olan altı işlem vardır: `key=value` seçeneklerinden bir motor oluşturmak, istek başlığı (`METHOD URL` ve başlık satırları) ile gövde uzunluğunu vererek bir istek başlatmak, istek gövdesi parçalarını yazmak, yanıt başlığını beklemek, çözülmüş gövdeyi okumak ve tutamaçları (handle) yok etmek. Bir istek tutamacı `@cancel` tanımlar; böylece terk edilen bir çağrı, isteğin tamamlanmasına kadar çalışmasına izin vermek yerine Chromium içinde isteği keser.

Yığını bir worker sürecinde izole etmek, paketleme kadar bir güvenlik özelliğidir de. Chromium'un ağ kodu, açık internetten gelen güvenilmeyen girdileri ayrıştırır. Çöktüğünde Go servisiniz onunla birlikte çökmez: çağrı bir hatayla başarısız olur, oturum atılır ve istemci bir sonraki ihtiyaçta yeni bir worker başlatır.

## Yeniden Üretilebilir Biçimde Derlenen, SHA-256 ile Sabitlenen

İçinde Chromium bulunan 25 MB'lık bir ikili, tam olarak neyin içine girdiğini söyleyebildiğiniz sürece güvenilirdir. `chromenet`, `gosuda.org/sqlite3`'ün SQLite'ı izlediği gibi Chromium Stable sürümünü izler: kaynak asla vendor edilmez, yalnızca pin'lenir.

| Pin                                                                                                                                          | Konum                          |
| :------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------- |
| Chromium sürümü ve resmi `-lite` kaynak arşivi                                                                                                | `third_party/chromium/VERSION` |
| Arşivin ve o sürümün pin'lediği her araç zincirinin SHA-256 değerleri: clang, Rust, GN, ninja, Windows clang çalışma zamanı, xwin           | `third_party/chromium/SHA256`  |
| xwin ile alınan MSVC CRT ve Windows SDK sürümleri                                                                                            | `third_party/chromium/WINSDK`  |
| Sandbox çalışma zamanı (`rungv`) sürümü, konuk imaj özeti, Debian snapshot tarihi                                                            | `scripts/engine/BUILDENV`      |
| HQQ C çalışma zamanı                                                                                                                         | `go.mod` ve `go.sum`           |

Mevcut pin Chromium `157.0.8103.38` sürümüdür. Pin'ine uymayan bir indirme derlemeyi durdurur. Sürüm, Chromium'a tam olarak bir yama uygular: Linux'ta `chrome_net_server`, NSS olmadan derlenir ve sunucu sertifikalarını yalnızca Chrome Root Store'a karşı doğrular; bu sayede ikili, libc dışında hiçbir şeye ihtiyaç duymaz.

Linux ve Windows motorları, [gvx](https://gosuda.org/blog/posts/gvx-cross-platform-linux-containers-z48916d01) sandbox'larının içinde derlenir: sabitlenmiş bir konuk imajına sahip, ayrıcalıksız süreçlerdir ve ana makinede bir daemon bulundurmazlar. Windows motorları, Linux üzerinde Chromium'un clang-cl ve lld-link araçlarıyla, xwin'in Microsoft'tan aldığı Windows SDK'ya karşı çapraz derlenir. macOS motorları ise macOS runner'ında yerel olarak derlenir; çünkü Chromium'un macOS derlemesi Xcode gerektirir.

Aynı commit'in yeniden derlenmesi, ayrı CI çalışmaları arasında bayt bayt aynı ikilileri üretti. Sürüm ikilileri, motoru monorepo'ya ekleyen commit için daha önce bir CI çalışmasının derlediği ikililerle, altı platformun tamamında bayt bayt aynıdır.

| Platform        | İkili boyutu |
| :-------------- | -----------: |
| `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 |

Linux motorları yalnızca `libc`, `libm`, `libdl`, `libpthread` ve `libgcc_s` kütüphanelerine bağlıdır ve glibc 2.31 veya daha yenisini gerektirir.

### Chromium'un ve Sürümlerin İzlenmesi

Zamanlanmış bir iş akışı, Chromium Stable sürümünü her altı saatte bir kontrol eder. Yeni bir sürüm bulunduğunda pin'leri yeniden yazar, `chromium/<version>` dalında altı motorun tamamını derleyip test eder, ikilileri onaylar ve pin'leri gömülü ikililer, özetleri ve lisans metinleriyle birlikte tek bir commit'te `main` dalına işler. Monorepo'da dosya bazlı `OWNERS` tanımları, iş akışının botuna yalnızca bu dosyaların güncellenme yetkisini verir; böylece güncelleme bir insan adımı olmadan birleşir. Ancak derleme tarifinin kendisindeki değişiklikler (Windows SDK pin'i ve yama) hâlâ bir sahibin onayını gerektirir.

Her sürüm ikilisi, onu derleyen iş akışından bir derleme kaynak doğrulama (build provenance attestation) taşır:

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

Her ikilinin içerdiği bileşenlerin lisans metinleri (Chromium, BoringSSL, QUICHE ve derleme grafiğinin geri kalanı), Chromium'un kendi `tools/licenses/licenses.py` aracıyla üretilir ve sürümle birlikte `NOTICE_<os>_<arch>.txt` dosyaları olarak dağıtılır.

## Sınırlamalar

- `DialWebSocket`, saf Go ile yazılmış bir RFC 6455 istemcisidir ve Chromium yığınını kullanmaz.
- `DialWebTransport`, süreç içi bir uygulamadır. Bir sunucuya ulaşmaz.
- Varsayılan JA4 ve HTTP/2 parmak izleri, sabitlenmiş Chromium sürümüne aittir. Chromium bunları sürümden sürüme değiştirir ve `chromenet` bu değişiklikleri takip eder.
- macOS ikilileri ad-hoc imzalıdır ve notarize edilmemiştir.
- Bir worker süreci bellek tüketir. Her motor ikilisi diskte 24 ila 28 MB yer kaplar ve Chromium çalışma zamanı bir iş parçacığı havuzu ile bir ağ iş parçacığı başlatır.
- Bir motor oturumu, yanıt gövdesi kapatılana kadar tutulur. Yanıt gövdelerini sızdıran bir program havuzu tüketir.

## Kaynak

Depo [github.com/gosuda/chromenet](https://github.com/gosuda/chromenet) adresinde yer alır ve gosuda monorepo'sundaki `//net/chromenet` dizininden yansıtılır. Derleme tarifi `scripts/engine` içinde, motor katmanı `engine/` içinde ve arayüz `chrome_net.idl` içinde bulunur.
