Skip to content

Commit 771dbc8

Browse files
committed
Added panic handling
1 parent f8aa489 commit 771dbc8

1 file changed

Lines changed: 33 additions & 10 deletions

File tree

fronted.go

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"net/http"
1515
"os"
1616
"path/filepath"
17+
"runtime/debug"
1718
"strings"
1819
"sync"
1920
"sync/atomic"
@@ -60,15 +61,16 @@ type fronted struct {
6061
providers map[string]*Provider
6162
clientHelloID tls.ClientHelloID
6263

63-
providersMu sync.RWMutex
64-
frontsMu sync.RWMutex
65-
stopCh chan interface{}
66-
crawlOnce sync.Once
67-
stopped atomic.Bool
68-
countryCode string
69-
httpClient *http.Client
70-
configURL string
71-
frontsCh chan Front
64+
providersMu sync.RWMutex
65+
frontsMu sync.RWMutex
66+
stopCh chan interface{}
67+
crawlOnce sync.Once
68+
stopped atomic.Bool
69+
countryCode string
70+
httpClient *http.Client
71+
configURL string
72+
frontsCh chan Front
73+
panicListener func(string)
7274
}
7375

7476
// Interface for sending HTTP traffic over domain fronting.
@@ -115,6 +117,7 @@ func NewFronted(options ...Option) Fronted {
115117
cacheFile: defaultCacheFilePath(),
116118
configURL: "",
117119
frontsCh: make(chan Front, 4000),
120+
panicListener: func(msg string) { log.Errorf("Panic in fronted: %v", msg) },
118121
}
119122

120123
for _, opt := range options {
@@ -157,6 +160,12 @@ func WithConfigURL(configURL string) Option {
157160
}
158161
}
159162

163+
func WithPanicListener(panicListener func(string)) Option {
164+
return func(f *fronted) {
165+
f.panicListener = panicListener
166+
}
167+
}
168+
160169
func defaultCacheFilePath() string {
161170
if dir, err := os.UserConfigDir(); err != nil {
162171
log.Errorf("Unable to get user config dir: %v", err)
@@ -187,6 +196,12 @@ func (f *fronted) keepCurrent() {
187196
)
188197

189198
go func() {
199+
// Recover from panics and log them
200+
defer func() {
201+
if r := recover(); r != nil {
202+
f.panicListener(fmt.Sprintf("Panic waiting for fronts %v with stack: %v", r, debug.Stack()))
203+
}
204+
}()
190205
for data := range chDB {
191206
log.Debug("Received new fronted configuration")
192207
f.onNewFrontsConfig(data)
@@ -241,7 +256,14 @@ func (f *fronted) onNewFronts(pool *x509.CertPool, providers map[string]*Provide
241256

242257
// The goroutine for finding working fronts runs forever, so only start it once.
243258
f.crawlOnce.Do(func() {
244-
go f.findWorkingFronts()
259+
go func() {
260+
defer func() {
261+
if r := recover(); r != nil {
262+
f.panicListener(fmt.Sprintf("Panic finding working fronts %v with stack: %v", r, debug.Stack()))
263+
}
264+
}()
265+
f.findWorkingFronts()
266+
}()
245267
})
246268
}
247269

@@ -607,6 +629,7 @@ func Vet(m *Masquerade, pool *x509.CertPool, testURL string) bool {
607629
certPool: atomic.Value{},
608630
maxAllowedCachedAge: defaultMaxAllowedCachedAge,
609631
maxCacheSize: defaultMaxCacheSize,
632+
panicListener: func(msg string) { log.Errorf("Panic in fronted: %v", msg) },
610633
}
611634
d.certPool.Store(pool)
612635
masq := &front{Masquerade: *m}

0 commit comments

Comments
 (0)