Fast, allocation-aware tools for validating, parsing, and iterating over HTTP and SOCKS proxies.
Note
Parsers and pools are safe for concurrent use. ParseInto, ParseString,
ParseBytes, and NextBytes support zero-allocation hot paths when
caller-owned storage is reused.
go get github.com/colduction/proxykit-go@latestRequires Go 1.26 or later.
| Package | Purpose |
|---|---|
proxykit |
Proxy model, URL export, and validation |
proxyparser |
Compiled custom-format parser |
proxypool |
Concurrent iteration over newline-delimited proxy files |
package main
import (
"fmt"
"github.com/colduction/proxykit-go"
)
func main() {
proxy := proxykit.Proxy{
Scheme: proxykit.HTTP,
Host: "proxy.example.com:8080",
Username: "user",
Password: "pass",
}
if proxy.IsValid() {
fmt.Println(proxy.ExportURL())
}
}Supported schemes are http, https, socks5, and socks5h. Host values
accept ASCII DNS host names, IPv4 addresses, and IPv6 addresses. Host-port
values use host:port for DNS and IPv4, and [ipv6]:port for IPv6.
DNS host names follow LDH rules: letters, decimal digits, and interior hyphens
inside dot-separated labels. Labels are limited to 63 bytes, full names are
limited to DNS presentation length, and absolute names may end with a root dot.
IPv6 zone identifiers are accepted in bracketed IPv6 host-port values such as
[fe80::1%eth0]:1080.
Validation is available through both Proxy methods and standalone helpers:
proxykit.IsValidScheme(proxykit.SOCKS5)
proxykit.IsValidHost("proxy.example.com")
proxykit.IsValidHost("2001:db8::1")
proxykit.IsValidHostnamePort("proxy.example.com:1080")
proxykit.IsValidHostnamePort("192.0.2.10:1080")
proxykit.IsValidHostnamePort("[2001:db8::1]:1080")
proxykit.IsValidCredentials("user", "pass")Use SplitHostnamePort when the caller needs to preserve whether the input
used IPv6 brackets before validating host and port separately.
Compile a format once and reuse it across goroutines:
package main
import (
"fmt"
"log"
"github.com/colduction/proxykit-go"
"github.com/colduction/proxykit-go/proxyparser"
)
func main() {
parser, err := proxyparser.New("%t://%u:%p@%h:%d", true)
if err != nil {
log.Fatal(err)
}
var proxy proxykit.Proxy
if err := parser.ParseInto(
"socks5://user:pass@proxy.example.com:1080",
&proxy,
); err != nil {
log.Fatal(err)
}
fmt.Println(proxy.ExportURL())
}For stack-friendly parsing, use ParseString:
proxy, err := parser.ParseString("http://proxy.example.com:8080")For file or network buffers, use ParseBytes. Parsed string fields alias the
input bytes, so keep the buffer immutable while the proxy value is in use:
var proxy proxykit.Proxy
buf := []byte("http://proxy.example.com:8080")
err := parser.ParseBytes(buf, &proxy)| Verb | Field |
|---|---|
%t |
Scheme |
%h |
Host |
%d |
Port |
%u |
Username |
%p |
Password |
%% |
Literal percent sign |
strict=true requires an exact match. Lenient mode tolerates missing optional
credentials or ports after a scheme and host are parsed.
Use errors.Is for sentinel errors such as ErrInvalidProxyFormat, and
errors.As for typed errors such as ErrInvalidFormatVerb.
Each input line is returned without its trailing CR or LF:
package main
import (
"fmt"
"log"
"github.com/colduction/proxykit-go/proxypool"
)
func main() {
pool, err := proxypool.New(
"proxies.txt",
proxypool.ModeSequential,
false,
)
if err != nil {
log.Fatal(err)
}
defer pool.Close()
for proxy, ok := pool.Next(); ok; proxy, ok = pool.Next() {
fmt.Println(proxy)
}
}| Mode | Behavior |
|---|---|
ModeSequential |
Streams proxies in file order without an index |
ModeShuffled |
Uses a <path>.idx sidecar and returns one permutation per cycle |
Set reuse=true to begin another cycle after the final proxy. For an
allocation-free read path, reuse a byte slice with NextBytes:
buf := make([]byte, 0, 128)
for {
var ok bool
buf, ok = pool.NextBytes(buf[:0])
if !ok {
break
}
consume(buf)
}Use Open with Options when the pool needs custom buffers, a custom index
path, persistent sidecar indexes, or preloaded shuffled reads:
pool, err := proxypool.Open("proxies.txt", proxypool.Options{
Mode: proxypool.ModeShuffled,
Reuse: true,
Preload: true,
IndexPath: "proxies.idx",
})Preload reads the proxy file into memory for shuffled mode. It avoids per-line
file I/O and keeps NextBytes allocation-free when the destination buffer has
enough capacity.
Stats reports file size, indexed line count, cursor, mode, reuse, preload,
and index behavior. Reset rewinds the pool to the start of its current cycle.
Important
Close releases pool resources. Pools created with New remove the shuffled
sidecar index on close. Pools created with Open keep it unless
Options.RemoveIndexOnClose is true.
Licensed under the MIT License.