+2
-6
src/caddy.go
+2
-6
src/caddy.go
···
6
6
"fmt"
7
7
"net"
8
8
"net/http"
9
-
"net/url"
10
9
"strings"
11
10
)
12
11
···
55
54
}
56
55
57
56
func tryDialWithSNI(ctx context.Context, domain string) (bool, error) {
58
-
if config.Fallback.ProxyTo == "" {
57
+
if config.Fallback.ProxyTo == nil {
59
58
return false, nil
60
59
}
61
60
62
-
fallbackURL, err := url.Parse(config.Fallback.ProxyTo)
63
-
if err != nil {
64
-
return false, err
65
-
}
61
+
fallbackURL := config.Fallback.ProxyTo
66
62
if fallbackURL.Scheme != "https" {
67
63
return false, nil
68
64
}
+39
-9
src/config.go
+39
-9
src/config.go
···
4
4
"bytes"
5
5
"encoding/json"
6
6
"fmt"
7
+
"net/url"
7
8
"os"
8
9
"reflect"
9
10
"slices"
···
16
17
"github.com/pelletier/go-toml/v2"
17
18
)
18
19
19
-
// For some reason, the standard `time.Duration` type doesn't implement the standard
20
+
// For an unknown reason, the standard `time.Duration` type doesn't implement the standard
20
21
// `encoding.{TextMarshaler,TextUnmarshaler}` interfaces.
21
22
type Duration time.Duration
22
23
···
26
27
27
28
func (t *Duration) UnmarshalText(data []byte) (err error) {
28
29
u, err := time.ParseDuration(string(data))
29
-
*t = Duration(u)
30
+
if err == nil {
31
+
*t = Duration(u)
32
+
}
30
33
return
31
34
}
32
35
···
34
37
return []byte(t.String()), nil
35
38
}
36
39
40
+
// For a known but upsetting reason, the standard `url.URL` type doesn't implement the standard
41
+
// `encoding.{TextMarshaler,TextUnmarshaler}` interfaces.
42
+
type URL struct {
43
+
url.URL
44
+
}
45
+
46
+
func (t *URL) String() string {
47
+
return fmt.Sprint(&t.URL)
48
+
}
49
+
50
+
func (t *URL) UnmarshalText(data []byte) (err error) {
51
+
u, err := url.Parse(string(data))
52
+
if err == nil {
53
+
*t = URL{*u}
54
+
}
55
+
return
56
+
}
57
+
58
+
func (t *URL) MarshalText() ([]byte, error) {
59
+
return []byte(t.String()), nil
60
+
}
61
+
37
62
type Config struct {
38
63
Insecure bool `toml:"-" env:"insecure"`
39
64
Features []string `toml:"features"`
···
56
81
57
82
type WildcardConfig struct {
58
83
Domain string `toml:"domain"`
59
-
CloneURL string `toml:"clone-url"`
84
+
CloneURL string `toml:"clone-url"` // URL template, not an exact URL
60
85
IndexRepos []string `toml:"index-repos" default:"[]"`
61
86
IndexRepoBranch string `toml:"index-repo-branch" default:"pages"`
62
87
Authorization string `toml:"authorization"`
63
88
}
64
89
65
90
type FallbackConfig struct {
66
-
ProxyTo string `toml:"proxy-to"`
67
-
Insecure bool `toml:"insecure"`
91
+
ProxyTo *URL `toml:"proxy-to"`
92
+
Insecure bool `toml:"insecure"`
68
93
}
69
94
70
95
type CacheConfig struct {
···
223
248
if valueCast, err = datasize.ParseString(repr); err == nil {
224
249
reflValue.Set(reflect.ValueOf(valueCast))
225
250
}
226
-
case time.Duration:
227
-
if valueCast, err = time.ParseDuration(repr); err == nil {
228
-
reflValue.Set(reflect.ValueOf(valueCast))
229
-
}
230
251
case Duration:
231
252
var parsed time.Duration
232
253
if parsed, err = time.ParseDuration(repr); err == nil {
233
254
reflValue.Set(reflect.ValueOf(Duration(parsed)))
255
+
}
256
+
case *URL:
257
+
if repr == "" {
258
+
reflValue.Set(reflect.ValueOf(nil))
259
+
} else {
260
+
var parsed *url.URL
261
+
if parsed, err = url.Parse(repr); err == nil {
262
+
reflValue.Set(reflect.ValueOf(&URL{*parsed}))
263
+
}
234
264
}
235
265
case []WildcardConfig:
236
266
var parsed []*WildcardConfig
+2
-8
src/main.go
+2
-8
src/main.go
···
67
67
}
68
68
69
69
func configureFallback(_ context.Context) (err error) {
70
-
if config.Fallback.ProxyTo != "" {
71
-
var fallbackURL *url.URL
72
-
fallbackURL, err = url.Parse(config.Fallback.ProxyTo)
73
-
if err != nil {
74
-
err = fmt.Errorf("fallback: %w", err)
75
-
return
76
-
}
77
-
70
+
if config.Fallback.ProxyTo != nil {
71
+
fallbackURL := &config.Fallback.ProxyTo.URL
78
72
fallback = &httputil.ReverseProxy{
79
73
Rewrite: func(r *httputil.ProxyRequest) {
80
74
r.SetURL(fallbackURL)