Skip to content

Commit 20f8d1f

Browse files
committed
Drop use of github.com/gorilla/mux
mux is replaced with a simple wrapper around http.ServeMux with middleware chain support Unfortunately github.com/rootless-containers/rootlesskit/pkg/parent still uses it so we can't drop the indirect dep yet. Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
1 parent 0a3f10c commit 20f8d1f

16 files changed

Lines changed: 236 additions & 126 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ require (
101101
github.com/google/cadvisor v0.53.0
102102
github.com/google/go-containerregistry v0.20.2
103103
github.com/google/uuid v1.6.0
104-
github.com/gorilla/mux v1.8.1
105104
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674
106105
github.com/inetaf/tcpproxy v0.0.0-20240214030015-3ce58045626c
107106
github.com/ipfs/go-ds-leveldb v0.5.0
@@ -299,6 +298,7 @@ require (
299298
github.com/google/go-tpm v0.9.6 // indirect
300299
github.com/google/gopacket v1.1.19 // indirect
301300
github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 // indirect
301+
github.com/gorilla/mux v1.8.1 // indirect
302302
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
303303
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect
304304
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.0 // indirect

pkg/agent/https/https.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import (
55
"strconv"
66
"sync"
77

8-
"github.com/gorilla/mux"
98
"github.com/k3s-io/k3s/pkg/daemons/config"
109
"github.com/k3s-io/k3s/pkg/server/auth"
1110
"github.com/k3s-io/k3s/pkg/util"
11+
"github.com/k3s-io/k3s/pkg/util/mux"
1212
"k8s.io/apiserver/pkg/server"
1313
"k8s.io/apiserver/pkg/server/options"
1414
)
@@ -25,7 +25,7 @@ var err error
2525
// Subsequent calls will return the same router.
2626
func Start(ctx context.Context, nodeConfig *config.Node, runtime *config.ControlRuntime) (*mux.Router, error) {
2727
once.Do(func() {
28-
router = mux.NewRouter().SkipClean(true)
28+
router = mux.NewRouter()
2929
config := &server.Config{}
3030

3131
if runtime == nil {

pkg/cli/agent/agent.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"path/filepath"
88
"sync"
99

10-
"github.com/gorilla/mux"
1110
"github.com/k3s-io/k3s/pkg/agent"
1211
"github.com/k3s-io/k3s/pkg/agent/https"
1312
"github.com/k3s-io/k3s/pkg/cli/cmds"
@@ -20,6 +19,7 @@ import (
2019
"github.com/k3s-io/k3s/pkg/spegel"
2120
"github.com/k3s-io/k3s/pkg/util"
2221
"github.com/k3s-io/k3s/pkg/util/errors"
22+
"github.com/k3s-io/k3s/pkg/util/mux"
2323
"github.com/k3s-io/k3s/pkg/util/permissions"
2424
"github.com/k3s-io/k3s/pkg/version"
2525
"github.com/k3s-io/k3s/pkg/vpn"

pkg/cli/server/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"time"
1212

1313
systemd "github.com/coreos/go-systemd/v22/daemon"
14-
"github.com/gorilla/mux"
1514
"github.com/k3s-io/k3s/pkg/agent"
1615
"github.com/k3s-io/k3s/pkg/agent/https"
1716
"github.com/k3s-io/k3s/pkg/agent/loadbalancer"
@@ -30,6 +29,7 @@ import (
3029
"github.com/k3s-io/k3s/pkg/spegel"
3130
"github.com/k3s-io/k3s/pkg/util"
3231
"github.com/k3s-io/k3s/pkg/util/errors"
32+
"github.com/k3s-io/k3s/pkg/util/mux"
3333
"github.com/k3s-io/k3s/pkg/util/permissions"
3434
"github.com/k3s-io/k3s/pkg/version"
3535
"github.com/k3s-io/k3s/pkg/vpn"

pkg/cluster/managed.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ import (
1313
"sync"
1414
"time"
1515

16-
"github.com/gorilla/mux"
1716
"github.com/k3s-io/k3s/pkg/cluster/managed"
1817
"github.com/k3s-io/k3s/pkg/etcd"
1918
"github.com/k3s-io/k3s/pkg/nodepassword"
2019
"github.com/k3s-io/k3s/pkg/util"
20+
"github.com/k3s-io/k3s/pkg/util/mux"
2121
"github.com/k3s-io/k3s/pkg/version"
2222
"github.com/sirupsen/logrus"
2323
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -144,10 +144,10 @@ func (c *Cluster) deleteNodePasswdSecret(ctx context.Context) {
144144

145145
// handlerNoEtcd wraps a handler with an error message indicating that etcd is not deployed.
146146
func handlerNoEtcd(handler http.Handler) http.Handler {
147-
r := mux.NewRouter().SkipClean(true)
147+
r := mux.NewRouter()
148148

149149
// Wildcard route for anything after /db/
150-
r.HandleFunc("/db/{_:.*}", func(resp http.ResponseWriter, r *http.Request) {
150+
r.HandleFunc("/db/", func(resp http.ResponseWriter, r *http.Request) {
151151
util.SendError(errors.New("etcd datastore disabled"), resp, r, http.StatusBadRequest)
152152
})
153153

pkg/etcd/etcd.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import (
1919
"time"
2020

2121
"github.com/google/uuid"
22-
"github.com/gorilla/mux"
2322
"github.com/k3s-io/k3s/pkg/clientaccess"
2423
"github.com/k3s-io/k3s/pkg/cluster/managed"
2524
"github.com/k3s-io/k3s/pkg/daemons/config"
@@ -31,6 +30,7 @@ import (
3130
"github.com/k3s-io/k3s/pkg/signals"
3231
"github.com/k3s-io/k3s/pkg/util"
3332
"github.com/k3s-io/k3s/pkg/util/errors"
33+
"github.com/k3s-io/k3s/pkg/util/mux"
3434
"github.com/k3s-io/k3s/pkg/version"
3535
kine "github.com/k3s-io/kine/pkg/app"
3636
"github.com/k3s-io/kine/pkg/client"
@@ -744,16 +744,16 @@ func (e *ETCD) setName(force bool) error {
744744

745745
// handler wraps the handler with routes for database info
746746
func (e *ETCD) handler(next http.Handler) http.Handler {
747-
r := mux.NewRouter().SkipClean(true)
747+
r := mux.NewRouter()
748748
r.NotFoundHandler = next
749749

750-
ir := r.Path("/db/info").Subrouter()
750+
ir := r.SubRouter("/db/info")
751751
ir.Use(auth.IsLocalOrHasRole(e.config, version.Program+":server"))
752-
ir.Handle("", e.infoHandler())
752+
ir.Handle("/", e.infoHandler())
753753

754-
sr := r.Path("/db/snapshot").Subrouter()
754+
sr := r.SubRouter("/db/snapshot")
755755
sr.Use(auth.HasRole(e.config, version.Program+":server"))
756-
sr.Handle("", e.snapshotHandler())
756+
sr.Handle("/", e.snapshotHandler())
757757

758758
return r
759759
}

pkg/etcd/s3/s3_test.go

Lines changed: 71 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ import (
1414
"text/template"
1515
"time"
1616

17-
"github.com/gorilla/mux"
1817
"github.com/k3s-io/k3s/pkg/daemons/config"
1918
"github.com/k3s-io/k3s/pkg/etcd/snapshot"
2019
"github.com/k3s-io/k3s/pkg/util"
20+
"github.com/k3s-io/k3s/pkg/util/mux"
2121
"github.com/k3s-io/k3s/tests/mock"
2222
"github.com/rancher/dynamiclistener/cert"
2323
"github.com/rancher/wrangler/v3/pkg/generated/controllers/core"
@@ -1554,65 +1554,72 @@ func s3Router(t *testing.T) http.Handler {
15541554
// badbucket returns 404 for all requests
15551555
// authbucket returns 200 for HeadBucket, 403 for all others
15561556
// others return 200 for objects with name prefix snapshot, 404 for all others
1557-
router := mux.NewRouter().SkipClean(true)
1557+
router := mux.NewRouter()
15581558
// HeadBucket
1559-
router.Path("/{bucket}/").Methods(http.MethodHead).HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
1560-
vars := mux.Vars(r)
1561-
if vars["bucket"] == "badbucket" {
1562-
rw.WriteHeader(http.StatusNotFound)
1563-
}
1564-
})
15651559
// ListObjectsV2
1566-
router.Path("/{bucket}/").Methods(http.MethodGet).HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
1567-
vars := mux.Vars(r)
1568-
switch vars["bucket"] {
1569-
case "badbucket":
1570-
rw.WriteHeader(http.StatusNotFound)
1571-
case "authbucket":
1572-
rw.WriteHeader(http.StatusForbidden)
1573-
default:
1574-
prefix := r.URL.Query().Get("prefix")
1575-
filtered := []object{}
1576-
for _, object := range objects {
1577-
if strings.HasPrefix(object.Key, prefix) {
1578-
filtered = append(filtered, object)
1579-
}
1560+
router.HandleFunc("GET /{bucket}/{$}", func(rw http.ResponseWriter, r *http.Request) {
1561+
switch r.Method {
1562+
case http.MethodHead:
1563+
if r.PathValue("bucket") == "badbucket" {
1564+
rw.WriteHeader(http.StatusNotFound)
15801565
}
1581-
if err := listResponse.Execute(rw, bucket{Name: vars["bucket"], Prefix: prefix, Objects: filtered}); err != nil {
1582-
t.Errorf("Failed to generate ListObjectsV2 response, error = %v", err)
1583-
rw.WriteHeader(http.StatusInternalServerError)
1566+
case http.MethodGet:
1567+
switch r.PathValue("bucket") {
1568+
case "badbucket":
1569+
rw.WriteHeader(http.StatusNotFound)
1570+
case "authbucket":
1571+
rw.WriteHeader(http.StatusForbidden)
1572+
default:
1573+
prefix := r.URL.Query().Get("prefix")
1574+
filtered := []object{}
1575+
for _, object := range objects {
1576+
if strings.HasPrefix(object.Key, prefix) {
1577+
filtered = append(filtered, object)
1578+
}
1579+
}
1580+
if err := listResponse.Execute(rw, bucket{Name: r.PathValue("bucket"), Prefix: prefix, Objects: filtered}); err != nil {
1581+
t.Errorf("Failed to generate ListObjectsV2 response, error = %v", err)
1582+
rw.WriteHeader(http.StatusInternalServerError)
1583+
}
15841584
}
15851585
}
15861586
})
1587-
// HeadObject - snapshot
1588-
router.Path("/{bucket}/{prefix:.*}snapshot-{snapshot}").Methods(http.MethodHead).HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
1589-
vars := mux.Vars(r)
1590-
switch vars["bucket"] {
1591-
case "badbucket":
1592-
rw.WriteHeader(http.StatusNotFound)
1593-
case "authbucket":
1594-
rw.WriteHeader(http.StatusForbidden)
1595-
default:
1596-
rw.Header().Add("last-modified", time.Now().In(gmt).Format(time.RFC1123))
1597-
}
1598-
})
1599-
// GetObject - snapshot
1600-
router.Path("/{bucket}/{prefix:.*}snapshot-{snapshot}").Methods(http.MethodGet).HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
1601-
vars := mux.Vars(r)
1602-
switch vars["bucket"] {
1603-
case "badbucket":
1604-
rw.WriteHeader(http.StatusNotFound)
1605-
case "authbucket":
1606-
rw.WriteHeader(http.StatusForbidden)
1607-
default:
1608-
rw.Header().Add("last-modified", time.Now().In(gmt).Format(time.RFC1123))
1609-
rw.Write([]byte("test snapshot file\n"))
1587+
// HeadObject
1588+
// GetObject
1589+
router.HandleFunc("GET /{bucket}/{object...}", func(rw http.ResponseWriter, r *http.Request) {
1590+
switch r.Method {
1591+
case http.MethodHead:
1592+
switch r.PathValue("bucket") {
1593+
case "badbucket":
1594+
rw.WriteHeader(http.StatusNotFound)
1595+
case "authbucket":
1596+
rw.WriteHeader(http.StatusForbidden)
1597+
default:
1598+
if strings.Contains(r.PathValue("object"), "bad") {
1599+
rw.WriteHeader(http.StatusNotFound)
1600+
} else {
1601+
rw.Header().Add("last-modified", time.Now().In(gmt).Format(time.RFC1123))
1602+
}
1603+
}
1604+
case http.MethodGet:
1605+
switch r.PathValue("bucket") {
1606+
case "badbucket":
1607+
rw.WriteHeader(http.StatusNotFound)
1608+
case "authbucket":
1609+
rw.WriteHeader(http.StatusForbidden)
1610+
default:
1611+
if strings.Contains(r.PathValue("object"), "bad") {
1612+
rw.WriteHeader(http.StatusNotFound)
1613+
} else {
1614+
rw.Header().Add("last-modified", time.Now().In(gmt).Format(time.RFC1123))
1615+
rw.Write([]byte("test snapshot file\n"))
1616+
}
1617+
}
16101618
}
16111619
})
1612-
// PutObject/DeleteObject - snapshot
1613-
router.Path("/{bucket}/{prefix:.*}snapshot-{snapshot}").Methods(http.MethodPut, http.MethodDelete).HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
1614-
vars := mux.Vars(r)
1615-
switch vars["bucket"] {
1620+
// PutObject
1621+
router.HandleFunc("PUT /{bucket}/{object...}", func(rw http.ResponseWriter, r *http.Request) {
1622+
switch r.PathValue("bucket") {
16161623
case "badbucket":
16171624
rw.WriteHeader(http.StatusNotFound)
16181625
case "authbucket":
@@ -1623,45 +1630,27 @@ func s3Router(t *testing.T) http.Handler {
16231630
}
16241631
}
16251632
})
1626-
// HeadObject - snapshot metadata
1627-
router.Path("/{bucket}/{prefix:.*}.metadata/snapshot-{snapshot}").Methods(http.MethodHead).HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
1628-
vars := mux.Vars(r)
1629-
switch vars["bucket"] {
1630-
case "badbucket":
1631-
rw.WriteHeader(http.StatusNotFound)
1632-
case "authbucket":
1633-
rw.WriteHeader(http.StatusForbidden)
1634-
default:
1635-
rw.Header().Add("last-modified", time.Now().In(gmt).Format(time.RFC1123))
1636-
}
1637-
})
1638-
// GetObject - snapshot metadata
1639-
router.Path("/{bucket}/{prefix:.*}.metadata/snapshot-{snapshot}").Methods(http.MethodGet).HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
1640-
vars := mux.Vars(r)
1641-
switch vars["bucket"] {
1642-
case "badbucket":
1643-
rw.WriteHeader(http.StatusNotFound)
1644-
case "authbucket":
1645-
rw.WriteHeader(http.StatusForbidden)
1646-
default:
1647-
rw.Header().Add("last-modified", time.Now().In(gmt).Format(time.RFC1123))
1648-
rw.Write([]byte("test snapshot metadata\n"))
1649-
}
1650-
})
1651-
// PutObject/DeleteObject - snapshot metadata
1652-
router.Path("/{bucket}/{prefix:.*}.metadata/snapshot-{snapshot}").Methods(http.MethodPut, http.MethodDelete).HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
1653-
vars := mux.Vars(r)
1654-
switch vars["bucket"] {
1633+
// DeleteObject
1634+
router.HandleFunc("DELETE /{bucket}/{object...}", func(rw http.ResponseWriter, r *http.Request) {
1635+
switch r.PathValue("bucket") {
16551636
case "badbucket":
16561637
rw.WriteHeader(http.StatusNotFound)
16571638
case "authbucket":
16581639
rw.WriteHeader(http.StatusForbidden)
16591640
default:
16601641
if r.Method == http.MethodDelete {
1661-
rw.WriteHeader(http.StatusNoContent)
1642+
if strings.Contains(r.PathValue("object"), "bad") {
1643+
rw.WriteHeader(http.StatusNotFound)
1644+
} else {
1645+
rw.WriteHeader(http.StatusNoContent)
1646+
}
16621647
}
16631648
}
16641649
})
1650+
router.NotFoundHandler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
1651+
logrus.Errorf("Failed to match %q", r.URL)
1652+
rw.WriteHeader(http.StatusInternalServerError)
1653+
})
16651654
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
16661655
scheme := "http"
16671656
if r.TLS != nil {

pkg/etcd/snapshot_handler.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/k3s-io/k3s/pkg/util"
1313
"github.com/k3s-io/k3s/pkg/util/errors"
1414
"github.com/sirupsen/logrus"
15+
apierrors "k8s.io/apimachinery/pkg/api/errors"
1516
)
1617

1718
type SnapshotOperation string
@@ -178,7 +179,7 @@ func (e *ETCD) withRequest(sr *SnapshotRequest) *ETCD {
178179
// getSnapshotRequest unmarshalls the snapshot operation request from a client.
179180
func getSnapshotRequest(req *http.Request) (*SnapshotRequest, error) {
180181
if req.Method != http.MethodPost {
181-
return nil, http.ErrNotSupported
182+
return nil, apierrors.NewMethodNotSupported(k3s.Resource("snapshot"), req.Method)
182183
}
183184
sr := &SnapshotRequest{}
184185
b, err := io.ReadAll(req.Body)

pkg/metrics/metrics.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import (
44
"context"
55
"errors"
66

7-
"github.com/gorilla/mux"
87
"github.com/k3s-io/k3s/pkg/agent/https"
98
"github.com/k3s-io/k3s/pkg/agent/loadbalancer"
109
"github.com/k3s-io/k3s/pkg/daemons/config"
1110
"github.com/k3s-io/k3s/pkg/etcd/snapshotmetrics"
11+
"github.com/k3s-io/k3s/pkg/util/mux"
1212
"github.com/prometheus/client_golang/prometheus/promhttp"
1313
lassometrics "github.com/rancher/lasso/pkg/metrics"
1414
rdmetrics "github.com/rancher/remotedialer/metrics"

pkg/nodepassword/validate.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ import (
1010
"sync"
1111
"time"
1212

13-
"github.com/gorilla/mux"
1413
"github.com/k3s-io/k3s/pkg/daemons/config"
1514
"github.com/k3s-io/k3s/pkg/util"
1615
"github.com/k3s-io/k3s/pkg/util/errors"
16+
"github.com/k3s-io/k3s/pkg/version"
1717
"github.com/sirupsen/logrus"
1818
corev1 "k8s.io/api/core/v1"
1919
"k8s.io/apimachinery/pkg/types"
@@ -105,13 +105,12 @@ func getNodeInfo(req *http.Request) (*nodeInfo, error) {
105105
return nil, errors.New("auth user not set")
106106
}
107107

108-
program := mux.Vars(req)["program"]
109-
nodeName := req.Header.Get(program + "-Node-Name")
108+
nodeName := req.Header.Get(version.Program + "-Node-Name")
110109
if nodeName == "" {
111110
return nil, errors.New("node name not set")
112111
}
113112

114-
nodePassword := req.Header.Get(program + "-Node-Password")
113+
nodePassword := req.Header.Get(version.Program + "-Node-Password")
115114
if nodePassword == "" {
116115
return nil, errors.New("node password not set")
117116
}

0 commit comments

Comments
 (0)