Documentation
¶
Overview ¶
Package unblock adalah HTTP client Go yang menyerupai browser (ClientHello dan HTTP/2 fingerprint Chrome) dan tahu kapan dirinya diblokir.
Tiga hal yang ditangani:
- TLS/JA3 dan HTTP/2 fingerprint — lewat bogdanfinn/tls-client, sehingga aturan WAF berbasis fingerprint tidak menolak request.
- Fallback HTTP/1.1 otomatis ketika server menolak HTTP/2 (RST_STREAM), dengan fingerprint TLS yang sama.
- Klasifikasi blokir — Cloudflare challenge, error 1009/1010/1015/1020, dan WAF pihak ketiga dibedakan satu sama lain, karena masing-masing butuh tindakan berbeda.
Paket ini TIDAK mengeksekusi JavaScript. Challenge Cloudflare yang butuh JS tetap tidak bisa dilewati di sini; Classify hanya memberi tahu bahwa itu yang terjadi.
Index ¶
Examples ¶
Constants ¶
const DefaultCooldownWindow = 6 * time.Hour
DefaultCooldownWindow dipakai bila NewCooldown menerima durasi nol.
const DefaultMaxBody = 5 << 20
DefaultMaxBody adalah batas ukuran body (5 MiB).
const DefaultTimeout = 20 * time.Second
DefaultTimeout adalah batas waktu per percobaan bila Options.Timeout kosong.
Variables ¶
var ErrNoBody = errors.New("unblock: empty body")
ErrNoBody dipakai saat respons tidak membawa data yang diharapkan.
Functions ¶
Types ¶
type Block ¶
type Block struct {
// Kind adalah kategori: CF_CHALLENGE, CF_BLOCK_1009, CF_BLOCK_1010,
// CF_BLOCK_1015, CF_BLOCK_1020, CF_BLOCK_GENERIC, WAF_GENERIC.
Kind string `json:"kind"`
// Code adalah kode error Cloudflare bila ada (mis. "1020").
Code string `json:"code,omitempty"`
// RayID berguna saat menghubungi support penyedia WAF atau pemilik situs.
RayID string `json:"ray_id,omitempty"`
// Server adalah nilai header Server.
Server string `json:"server,omitempty"`
// Hint menyarankan tindakan berikutnya.
Hint string `json:"hint,omitempty"`
}
Block menjelaskan satu peristiwa blokir.
func Classify ¶
Classify memeriksa apakah respons merupakan blokir WAF/anti-bot. Mengembalikan nil bila bukan blokir.
Empat situasi berbeda bersembunyi di balik HTTP 403, dan masing-masing butuh respons yang berbeda — jangan pernah memperlakukannya sebagai satu kasus.
Example ¶
Contoh membedakan jenis blokir.
package main
import (
"fmt"
"net/http"
"github.com/nyelonong/unblock"
)
func main() {
h := http.Header{}
h.Set("Server", "cloudflare")
h.Set("Cf-Ray", "8a1b2c3d-JKT")
resp := &unblock.Response{
StatusCode: 403,
Header: h,
Body: []byte("<title>Attention Required!</title><h2>Error 1020</h2>"),
}
b := unblock.Classify(resp)
fmt.Println(b.Kind, b.Code, b.Challenge())
fmt.Println(b.Hint)
}
Output: CF_BLOCK_1020 1020 false firewall rule menolak ASN/datacenter: perlu proxy residensial
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client adalah fetcher dengan fingerprint browser.
func New ¶
New membuat Client. Konfigurasi yang tidak valid tidak membuat New gagal: Client akan memakai fallback tanpa impersonation (net/http) supaya pemanggil tidak perlu menangani error di jalur inisialisasi.
func (*Client) Do ¶
Do menjalankan request dan mengembalikan body lengkap.
Bila percobaan pertama gagal karena masalah HTTP/2 (RST_STREAM, INTERNAL_ERROR), request diulang sekali lewat HTTP/1.1 dengan fingerprint TLS yang sama. Separuh budget waktu disisakan untuk percobaan kedua.
func (*Client) Get ¶
Get mengambil URL. Request mengikuti redirect secara default.
Example ¶
Contoh mengambil halaman dengan fingerprint browser.
package main
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"time"
"github.com/nyelonong/unblock"
)
func main() {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte("<html>halo</html>"))
}))
defer srv.Close()
c := unblock.New(unblock.Options{Profile: "chrome_133", Timeout: 5 * time.Second})
resp, err := c.Get(context.Background(), srv.URL)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(resp.StatusCode, len(resp.Body) > 0, resp.Blocked() == nil)
}
Output: 200 true true
type Cooldown ¶
type Cooldown struct {
// contains filtered or unexported fields
}
Cooldown mencatat host yang baru saja memblokir kita.
Blokir Cloudflare bersifat "sticky": mengulang request ke host yang sama dalam waktu singkat justru menaikkan level blokir (challenge menjadi block). Cooldown memberi jarak sebelum host itu dicoba lagi.
Example ¶
Contoh memakai cooldown per host.
package main
import (
"fmt"
"time"
"github.com/nyelonong/unblock"
)
func main() {
cd := unblock.NewCooldown(time.Hour)
host := unblock.HostOf("https://contoh.id/halaman")
fmt.Println(cd.Allow(host))
cd.Mark(host)
fmt.Println(cd.Allow(host))
}
Output: true false
func NewCooldown ¶
NewCooldown membuat Cooldown dengan jendela tertentu. Nol berarti DefaultCooldownWindow.
type Options ¶
type Options struct {
// Profile adalah nama preset TLS, mis. "chrome_133" atau "firefox_135".
// Kosong berarti profil Chrome default paket (versi terbaru yang didukung).
// Lihat profiles.MappedTLSClients untuk daftar lengkap.
Profile string
// ProxyURL opsional: "http://127.0.0.1:8080" atau "socks5://10.0.0.2:1080".
ProxyURL string
// Timeout per percobaan. Kosong berarti DefaultTimeout.
Timeout time.Duration
// MaxBody membatasi jumlah byte body yang dibaca. Kosong berarti DefaultMaxBody.
MaxBody int64
// Headers ditambahkan ke setiap request. Header yang sudah diatur profil
// TLS (user-agent, accept, dsb) akan ditimpa oleh nilai di sini.
Headers map[string]string
// ForceHTTP1 mematikan negosiasi HTTP/2 sepenuhnya. Berguna untuk server
// yang men-tarpit atau menolak h2 secara konsisten.
ForceHTTP1 bool
}
Options mengatur perilaku Client.
type Response ¶
type Response struct {
StatusCode int
Header http.Header
Body []byte
FinalURL string
// Attempts berisi 1 untuk percobaan pertama, 2 bila fallback HTTP/1.1 dipakai.
Attempts int
// HTTP1 bernilai true bila respons datang dari jalur fallback HTTP/1.1.
HTTP1 bool
}
Response adalah respons yang sudah dibaca penuh (dibatasi MaxBody).