Skip to content

Commit 1cf38c1

Browse files
authored
feat(worker): deliverer proxy (#254)
1 parent c8c9882 commit 1cf38c1

File tree

20 files changed

+969
-41
lines changed

20 files changed

+969
-41
lines changed

app/app.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,29 @@ func (app *Application) initialize() error {
174174

175175
// worker
176176
if cfg.Worker.Enabled {
177+
d := deliverer.NewHTTPDeliverer(deliverer.Options{
178+
Logger: log,
179+
RequestTimeout: time.Duration(cfg.Worker.Deliverer.Timeout) * time.Millisecond,
180+
AccessControlOptions: deliverer.AccessControlOptions{
181+
Deny: cfg.Worker.Deliverer.ACL.Deny,
182+
},
183+
})
184+
if cfg.Worker.Deliverer.Proxy != "" {
185+
err := d.SetupProxy(deliverer.ProxyOptions{
186+
URL: cfg.Worker.Deliverer.Proxy,
187+
TLSCert: cfg.Worker.Deliverer.ProxyTLSCert,
188+
TLSKey: cfg.Worker.Deliverer.ProxyTLSKey,
189+
TLSCaCertificate: cfg.Worker.Deliverer.ProxyTLSCaCert,
190+
TLSVerify: cfg.Worker.Deliverer.ProxyTLSVerify,
191+
})
192+
if err != nil {
193+
return err
194+
}
195+
}
177196
opts := worker.Options{
178197
PoolSize: int(cfg.Worker.Pool.Size),
179198
PoolConcurrency: int(cfg.Worker.Pool.Concurrency),
180-
Deliverer: deliverer.NewHTTPDeliverer(&cfg.Worker.Deliverer),
199+
Deliverer: d,
181200
DB: db,
182201
Srv: app.srv,
183202
Tracer: tracer,

config.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,15 @@ worker:
9191
# - '2606:2800:220:1:248:1893:25c8:1946'
9292
# - '*.example.com'
9393
#
94+
#proxy: # Proxy server URL. Supports HTTP and HTTPS.
95+
# When a proxy is enabled, the ACL is automatically disabled.
96+
# Example of HTTP: http://<host>:<port>
97+
# Example of HTTPS: https://<host>:<port>
98+
#proxy_tls_cert: # Path to the client certificate file used for mTLS proxy authentication.
99+
#proxy_tls_key: # Path to the client private key file used for mTLS proxy authentication.
100+
#proxy_tls_ca_cert: # Path to the CA certificate file used to verify the HTTPS proxy’s certificate.
101+
#proxy_tls_verify: true # Whether to verify the proxy server's TLS certificate.
102+
94103
pool:
95104
size: 10000 # pool size, default to 10000.
96105
concurrency: 0 # pool concurrency, default to 100 * CPUs

config/config_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,54 @@ func TestWorkerConfig(t *testing.T) {
431431
}
432432
}
433433

434+
func TestWorkerProxyConfig(t *testing.T) {
435+
tests := []struct {
436+
desc string
437+
cfg WorkerDeliverer
438+
validateErr error
439+
}{
440+
{
441+
desc: "sanity",
442+
cfg: WorkerDeliverer{
443+
Proxy: "http://example.com:8080",
444+
},
445+
validateErr: nil,
446+
},
447+
{
448+
desc: "invalid proxy url: missing schema",
449+
cfg: WorkerDeliverer{
450+
Proxy: "example.com",
451+
},
452+
validateErr: errors.New("invalid proxy url: 'example.com'"),
453+
},
454+
{
455+
desc: "invalid proxy url: invalid schema ",
456+
cfg: WorkerDeliverer{
457+
Proxy: "ftp://example.com",
458+
},
459+
validateErr: errors.New("proxy schema must be http or https"),
460+
},
461+
{
462+
desc: "invalid proxy url: missing host ",
463+
cfg: WorkerDeliverer{
464+
Proxy: "http://",
465+
},
466+
validateErr: errors.New("invalid proxy url: 'http://'"),
467+
},
468+
{
469+
desc: "invalid proxy url: missing host ",
470+
cfg: WorkerDeliverer{
471+
Proxy: "http ://",
472+
},
473+
validateErr: errors.New("invalid proxy url: parse \"http ://\": first path segment in URL cannot contain colon"),
474+
},
475+
}
476+
for _, test := range tests {
477+
actual := test.cfg.Validate()
478+
assert.Equal(t, test.validateErr, actual, "expected %v got %v", test.validateErr, actual)
479+
}
480+
}
481+
434482
func TestConfig(t *testing.T) {
435483
cfg, err := Init()
436484
assert.Nil(t, err)

config/worker.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,19 @@ package config
33
import (
44
"fmt"
55
"net/netip"
6+
"net/url"
67
"regexp"
78
"slices"
89
)
910

1011
type WorkerDeliverer struct {
11-
Timeout int64 `yaml:"timeout" json:"timeout" default:"60000"`
12-
ACL ACLConfig `yaml:"acl" json:"acl"`
12+
Timeout int64 `yaml:"timeout" json:"timeout" default:"60000"`
13+
ACL ACLConfig `yaml:"acl" json:"acl"`
14+
Proxy string `yaml:"proxy" json:"proxy"`
15+
ProxyTLSCert string `yaml:"proxy_tls_cert" json:"proxy_tls_cert" envconfig:"PROXY_TLS_CERT"`
16+
ProxyTLSKey string `yaml:"proxy_tls_key" json:"proxy_tls_key" envconfig:"PROXY_TLS_KEY"`
17+
ProxyTLSCaCert string `yaml:"proxy_tls_ca_cert" json:"proxy_tls_ca_cert" envconfig:"PROXY_TLS_CA_CERT"`
18+
ProxyTLSVerify bool `yaml:"proxy_tls_verify" json:"proxy_tls_verify" envconfig:"PROXY_TLS_VERIFY"`
1319
}
1420

1521
func (cfg *WorkerDeliverer) Validate() error {
@@ -19,6 +25,19 @@ func (cfg *WorkerDeliverer) Validate() error {
1925
if err := cfg.ACL.Validate(); err != nil {
2026
return err
2127
}
28+
if cfg.Proxy != "" {
29+
u, err := url.Parse(cfg.Proxy)
30+
if err != nil {
31+
return fmt.Errorf("invalid proxy url: %s", err)
32+
}
33+
if u.Scheme == "" || u.Host == "" {
34+
return fmt.Errorf("invalid proxy url: '%s'", cfg.Proxy)
35+
}
36+
if u.Scheme != "http" && u.Scheme != "https" {
37+
return fmt.Errorf("proxy schema must be http or https")
38+
}
39+
}
40+
2241
return nil
2342
}
2443

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef
88
github.com/creasty/defaults v1.8.0
99
github.com/dop251/goja v0.0.0-20250309171923-bcd7cc6bf64c
10+
github.com/elazarl/goproxy v1.7.2
1011
github.com/getkin/kin-openapi v0.132.0
1112
github.com/go-kit/kit v0.13.0
1213
github.com/go-playground/validator/v10 v10.26.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4
4848
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
4949
github.com/dop251/goja v0.0.0-20250309171923-bcd7cc6bf64c h1:mxWGS0YyquJ/ikZOjSrRjjFIbUqIP9ojyYQ+QZTU3Rg=
5050
github.com/dop251/goja v0.0.0-20250309171923-bcd7cc6bf64c/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4=
51+
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
52+
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
5153
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
5254
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
5355
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=

0 commit comments

Comments
 (0)