Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions acme/acme.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ func IssueCertificates(cacheDir, email, challengeType string, domains []string,

cfg.Issuers = append(cfg.Issuers, myAcme)

for i := range domains {
err := cfg.ObtainCertAsync(context.Background(), domains[i])
for _, domain := range domains {
err := cfg.ObtainCertAsync(context.Background(), domain)
if err != nil {
return nil, err
}
Expand Down
8 changes: 4 additions & 4 deletions config/uploads.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ func (cfg *Uploads) InitDefaults() error {
cfg.Forbidden = make(map[string]struct{})
cfg.Allowed = make(map[string]struct{})

for i := range cfg.Forbid {
cfg.Forbidden[cfg.Forbid[i]] = struct{}{}
for _, ext := range cfg.Forbid {
cfg.Forbidden[ext] = struct{}{}
}

for i := range cfg.Allow {
cfg.Allowed[cfg.Allow[i]] = struct{}{}
for _, ext := range cfg.Allow {
cfg.Allowed[ext] = struct{}{}
}

for k := range cfg.Forbidden {
Expand Down
10 changes: 10 additions & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2087,6 +2087,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw=
Expand Down Expand Up @@ -2566,6 +2568,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
Expand Down Expand Up @@ -2682,6 +2685,8 @@ go.temporal.io/api v1.28.0/go.mod h1:sAtVCXkwNaCtHVMP6B/FlK8PcEnaDjJ+KHCwS/ufscI
go.temporal.io/api v1.30.0 h1:6U/6lgpXf4UCywYxL3YfssqeI7IQnt9yNzwlfozUi2o=
go.temporal.io/api v1.30.0/go.mod h1:PIZ+UyGTMh3HJFauMysfanNBAh3f0jRf1xydrhTEcSQ=
go.temporal.io/api v1.57.0/go.mod h1:iaxoP/9OXMJcQkETTECfwYq4cw/bj4nwov8b3ZLVnXM=
go.temporal.io/api v1.62.2 h1:jFhIzlqNyJsJZTiCRQmTIMv6OTQ5BZ57z8gbgLGMaoo=
go.temporal.io/api v1.62.2/go.mod h1:iaxoP/9OXMJcQkETTECfwYq4cw/bj4nwov8b3ZLVnXM=
go.temporal.io/sdk v1.26.0-rc.2 h1:0NX4wR2qwD6xCv+JNhZdViamsITMYWzZkUqBJEIVHBw=
go.temporal.io/sdk v1.26.0-rc.2/go.mod h1:HDr8fIWJ/HF8dJwTPgOayI8PYB5WoVIxUMjzE78M2ng=
go.temporal.io/sdk/contrib/opentelemetry v0.4.0 h1:Ddx+39cESh4CNFI6cy8TI1OBJC8MUQUDzt6TpIJJjPQ=
Expand Down Expand Up @@ -2871,6 +2876,7 @@ golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=
golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
Expand Down Expand Up @@ -3231,6 +3237,7 @@ google.golang.org/genproto/googleapis/api v0.0.0-20250929231259-57b25ae835d4/go.
google.golang.org/genproto/googleapis/api v0.0.0-20251103181224-f26f9409b101/go.mod h1:E17fc4PDhkr22dE3RgnH2hEubUaky6ZwW4VhANxyspg=
google.golang.org/genproto/googleapis/api v0.0.0-20251124214823-79d6a2a48846/go.mod h1:Fk4kyraUvqD7i5H6S43sj2W98fbZa75lpZz/eUyhfO0=
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto=
google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d h1:EocjzKLywydp5uZ5tJ79iP6Q0UjDnyiHkGRWxuPBP8s=
google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:48U2I+QQUYhsFrg2SY6r+nJzeOtjey7j//WBESw+qyQ=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc h1:g3hIDl0jRNd9PPTs2uBzYuaD5mQuwOkZY0vSc0LR32o=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20240125205218-1f4bbc51befe h1:weYsP+dNijSQVoLAb5bpUos3ciBpNU/NEVlHFKrk8pg=
Expand All @@ -3257,6 +3264,7 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101/go.
google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d h1:t/LOSXPJ9R0B6fnZNyALBRfZBH0Uy0gT+uR+SJ6syqQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
Expand Down Expand Up @@ -3285,6 +3293,8 @@ google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd
google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
Expand Down
133 changes: 125 additions & 8 deletions handler/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func TestServeHTTP_InvalidMultipart_Returns400(t *testing.T) {
h := newTestHandler(t, defaultCfg(), nil)

// Boundary declared in header but body has no valid multipart parts → EOF.
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(""))
req := httptest.NewRequestWithContext(t.Context(), http.MethodPost, "/", strings.NewReader(""))
req.Header.Set("Content-Type", "multipart/form-data; boundary=1111")

rr := httptest.NewRecorder()
Expand All @@ -73,7 +73,7 @@ func TestServeHTTP_InvalidMultipart_Returns400(t *testing.T) {
func TestServeHTTP_StreamBody_MaxBytesExceeded_Returns413(t *testing.T) {
h := newTestHandler(t, defaultCfg(), nil)

req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader("this body is too long"))
req := httptest.NewRequestWithContext(t.Context(), http.MethodPost, "/", strings.NewReader("this body is too long"))
req.Header.Set("Content-Type", "application/json")

rr := httptest.NewRecorder()
Expand All @@ -92,7 +92,7 @@ func TestServeHTTP_TruncatedMultipart_Returns400(t *testing.T) {

// Multipart body with an open part but no closing boundary → ErrUnexpectedEOF.
body := "--1111\r\nContent-Disposition: form-data; name=\"f\"\r\n\r\nval"
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(body))
req := httptest.NewRequestWithContext(t.Context(), http.MethodPost, "/", strings.NewReader(body))
req.Header.Set("Content-Type", "multipart/form-data; boundary=1111")

rr := httptest.NewRecorder()
Expand Down Expand Up @@ -150,7 +150,7 @@ func TestHandleError_DebugMode_WritesEscapedError(t *testing.T) {
}

func TestURI_PlainHTTP(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/path?q=1", nil)
r := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/path?q=1", nil)
r.Host = "example.com"

got := URI(r)
Expand All @@ -161,7 +161,7 @@ func TestURI_PlainHTTP(t *testing.T) {
}

func TestURI_TLSRequest_HTTPSScheme(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/path?q=1", nil)
r := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/path?q=1", nil)
r.Host = "example.com"
r.TLS = &tls.ConnectionState{}

Expand All @@ -173,7 +173,7 @@ func TestURI_TLSRequest_HTTPSScheme(t *testing.T) {
}

func TestURI_StripsCRLFInjection(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/path", nil)
r := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/path", nil)
r.Host = "example.com"
// Inject CRLF into the raw query — a classic HTTP response-splitting vector.
r.URL.RawQuery = "param=value\r\nX-Injected: true"
Expand Down Expand Up @@ -206,7 +206,7 @@ func TestServeHTTP_PoolExecError_Returns500(t *testing.T) {
mp := &mockPool{execErr: fmt.Errorf("worker died")}
h := newTestHandler(t, defaultCfg(), mp)

req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(`{"key":"val"}`))
req := httptest.NewRequestWithContext(t.Context(), http.MethodPost, "/", strings.NewReader(`{"key":"val"}`))
req.Header.Set("Content-Type", "application/json")

rr := httptest.NewRecorder()
Expand All @@ -217,11 +217,128 @@ func TestServeHTTP_PoolExecError_Returns500(t *testing.T) {
}
}

// ── Group B′: FetchIP edge cases ─────────────────────────────────────────────

func TestFetchIP_EdgeCases(t *testing.T) {
tests := []struct {
name string
input string
want string
}{
{"empty string", "", ""},
{"ipv4 no port", "10.0.0.1", "10.0.0.1"},
{"ipv6 bracketed with port", "[::1]:8080", "::1"},
{"ipv6 full address bare", "2001:db8::1", "2001:db8::1"},
{"garbage with colons", "not:a:valid:thing", ""},
{"port only", ":8080", ""},
{"ipv4 with empty port", "127.0.0.1:", "127.0.0.1"},
{"ipv6 full with port", "[2001:db8::1]:443", "2001:db8::1"},
}

log := zap.NewNop()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := FetchIP(tt.input, log)
if got != tt.want {
t.Errorf("FetchIP(%q) = %q, want %q", tt.input, got, tt.want)
}
})
}
}

// ── Group B″: URI edge cases ─────────────────────────────────────────────────

func TestURI_EdgeCases(t *testing.T) {
tests := []struct {
name string
setup func() *http.Request
want string
}{
{
name: "empty host",
setup: func() *http.Request {
r := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil)
r.Host = ""
return r
},
want: "http:///",
},
{
name: "host with port",
setup: func() *http.Request {
r := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/p", nil)
r.Host = "example.com:8080"
return r
},
want: "http://example.com:8080/p",
},
{
name: "url already has host set",
setup: func() *http.Request {
r := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/x", nil)
r.URL.Host = "other.com"
return r
},
want: "//other.com/x",
},
{
name: "root path only",
setup: func() *http.Request {
r := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil)
r.Host = "example.com"
return r
},
want: "http://example.com/",
},
{
name: "query but no path",
setup: func() *http.Request {
r := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil)
r.Host = "example.com"
r.URL.Path = ""
r.URL.RawQuery = "a=1"
return r
},
want: "http://example.com?a=1",
},
{
name: "encoded CRLF in path preserved",
setup: func() *http.Request {
r := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/foo%0D%0Abar", nil)
r.Host = "example.com"
return r
},
want: "http://example.com/foo%0D%0Abar",
},
{
name: "tab in query not stripped",
setup: func() *http.Request {
r := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil)
r.Host = "example.com"
r.URL.RawQuery = "x=1\tX-Bad: true"
return r
},
want: "http://example.com/?x=1\tX-Bad: true",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := URI(tt.setup())
if got != tt.want {
t.Errorf("URI() = %q, want %q", got, tt.want)
}
})
}
}

// ── Group C: mockPool tests ───────────────────────────────────────────────────

func TestServeHTTP_NoFreeWorkers_SetsHeader(t *testing.T) {
mp := &mockPool{execErr: errors.E(errors.NoFreeWorkers)}
h := newTestHandler(t, defaultCfg(), mp)

req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(`{"key":"val"}`))
req := httptest.NewRequestWithContext(t.Context(), http.MethodPost, "/", strings.NewReader(`{"key":"val"}`))
req.Header.Set("Content-Type", "application/json")

rr := httptest.NewRecorder()
Expand Down
4 changes: 2 additions & 2 deletions handler/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ func (h *Handler) handlePROTOresponse(pld *payload.Payload, w http.ResponseWrite
push := rsp.GetHeaders()[HTTP2Push].GetValues()

if pusher, ok := w.(http.Pusher); ok {
for i := range push {
err = pusher.Push(string(rsp.GetHeaders()[HTTP2Push].GetValues()[i]), nil)
for _, pushVal := range push {
err = pusher.Push(string(pushVal), nil)
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions handler/uploads.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (u *Uploads) Open(log *zap.Logger, dir string, forbid, allow map[string]str
func (u *Uploads) Clear(log *zap.Logger) {
for _, f := range u.list {
if f.TempFilename != "" && exists(f.TempFilename) {
err := os.Remove(f.TempFilename) //nolint:gosec
err := os.Remove(f.TempFilename)
if err != nil && log != nil {
log.Error("error removing the file", zap.Error(err))
}
Expand Down Expand Up @@ -164,7 +164,7 @@ func (f *FileUpload) Open(dir string, forbid, allow map[string]struct{}) error {

// exists if file exists.
func exists(path string) bool {
if _, err := os.Stat(path); os.IsNotExist(err) { //nolint:gosec
if _, err := os.Stat(path); os.IsNotExist(err) {
return false
}
return true
Expand Down
6 changes: 3 additions & 3 deletions init.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,16 @@ func nilOr(cfg *config.Config) *acme.Config {

func (p *Plugin) applyBundledMiddleware() {
// apply max_req_size and logger middleware
for i := range p.servers {
switch srv := p.servers[i].Server().(type) {
for _, s := range p.servers {
switch srv := s.Server().(type) {
case *http.Server:
srv.Handler = bundledMw.MaxRequestSize(srv.Handler, p.cfg.MaxRequestSize*MB)
srv.Handler = bundledMw.NewLogMiddleware(srv.Handler, p.cfg.AccessLogs, p.log)
case *http3.Server:
srv.Handler = bundledMw.MaxRequestSize(srv.Handler, p.cfg.MaxRequestSize*MB)
srv.Handler = bundledMw.NewLogMiddleware(srv.Handler, p.cfg.AccessLogs, p.log)
default:
p.log.DPanic("unknown server type", zap.Any("server", p.servers[i].Server()))
p.log.DPanic("unknown server type", zap.Any("server", s.Server()))
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,14 @@ func (s *StatsExporter) Collect(ch chan<- prometheus.Metric) {
var invalid float64

// collect the memory
for i := range workerStates {
cum += float64(workerStates[i].MemoryUsage)
for _, ws := range workerStates {
cum += float64(ws.MemoryUsage)

ch <- prometheus.MustNewConstMetric(s.StateDesc, prometheus.GaugeValue, 0, workerStates[i].StatusStr, strconv.Itoa(int(workerStates[i].Pid)))
ch <- prometheus.MustNewConstMetric(s.WorkerMemoryDesc, prometheus.GaugeValue, float64(workerStates[i].MemoryUsage), strconv.Itoa(int(workerStates[i].Pid)))
ch <- prometheus.MustNewConstMetric(s.StateDesc, prometheus.GaugeValue, 0, ws.StatusStr, strconv.Itoa(int(ws.Pid)))
ch <- prometheus.MustNewConstMetric(s.WorkerMemoryDesc, prometheus.GaugeValue, float64(ws.MemoryUsage), strconv.Itoa(int(ws.Pid)))

// sync with sdk/worker/state.go
switch workerStates[i].Status {
switch ws.Status {
case fsm.StateReady:
ready++
case fsm.StateWorking:
Expand Down
15 changes: 11 additions & 4 deletions middleware/redirect.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package middleware

import (
"fmt"
"net"
"net/http"
"net/url"
"strconv"
"strings"
)

Expand All @@ -26,11 +27,17 @@ func Redirect(_ http.Handler, port int) http.Handler {

// TLSAddr replaces listen or host port with port configured by SSLConfig config.
func TLSAddr(host string, forcePort bool, sslPort int) string {
// remove current forcePort first
host = strings.Split(host, ":")[0]
if u, err := url.Parse("//" + host); err == nil {
host = u.Hostname()
}

if forcePort || sslPort != 443 {
host = fmt.Sprintf("%s:%v", host, sslPort)
return net.JoinHostPort(host, strconv.Itoa(sslPort))
}

// url.URL.Host requires bracketed IPv6 literals even without a port.
if strings.Contains(host, ":") {
return "[" + host + "]"
}

return host
Expand Down
Loading
Loading