Skip to content
Draft
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
50 changes: 26 additions & 24 deletions cmd/incusd/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import (
"strings"
"time"

"github.com/gorilla/mux"

clusterConfig "github.com/lxc/incus/v6/internal/server/cluster/config"
clusterRequest "github.com/lxc/incus/v6/internal/server/cluster/request"
"github.com/lxc/incus/v6/internal/server/db"
Expand Down Expand Up @@ -66,17 +64,14 @@ import (
// example: ["/1.0"]
func restServer(d *Daemon) *http.Server {
/* Setup the web server */
router := mux.NewRouter()
router.StrictSlash(false) // Don't redirect to URL with trailing slash.
router.SkipClean(true)
router.UseEncodedPath() // Allow encoded values in path segments.
router := http.NewServeMux()

// Serving the UI.
uiPath := os.Getenv("INCUS_UI")
uiEnabled := uiPath != "" && util.PathExists(fmt.Sprintf("%s/index.html", uiPath))
if uiEnabled {
uiHttpDir := uiHttpDir{http.Dir(uiPath)}
router.PathPrefix("/ui/").Handler(http.StripPrefix("/ui/", http.FileServer(uiHttpDir)))
router.Handle("/ui/", http.FileServer(uiHttpDir))
router.HandleFunc("/ui", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/ui/", http.StatusMovedPermanently)
})
Expand All @@ -87,7 +82,7 @@ func restServer(d *Daemon) *http.Server {
docEnabled := documentationPath != "" && util.PathExists(documentationPath)
if docEnabled {
documentationHttpDir := documentationHttpDir{http.Dir(documentationPath)}
router.PathPrefix("/documentation/").Handler(http.StripPrefix("/documentation/", http.FileServer(documentationHttpDir)))
router.Handle("/documentation/", http.FileServer(documentationHttpDir))
router.HandleFunc("/documentation", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/documentation/", http.StatusMovedPermanently)
})
Expand Down Expand Up @@ -166,14 +161,14 @@ func restServer(d *Daemon) *http.Server {
d.createCmd(router, "", c)
}

router.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
notFoundHandler := func(w http.ResponseWriter, r *http.Request) {
logger.Info("Sending top level 404", logger.Ctx{"url": r.URL, "method": r.Method, "remote": r.RemoteAddr})
w.Header().Set("Content-Type", "application/json")
_ = response.NotFound(nil).Render(w)
})
}

return &http.Server{
Handler: &httpServer{r: router, d: d},
Handler: &httpServer{r: router, d: d, n: notFoundHandler},
ConnContext: request.SaveConnectionInContext,
IdleTimeout: 30 * time.Second,
}
Expand Down Expand Up @@ -203,9 +198,7 @@ func vSockServer(d *Daemon) *http.Server {

func metricsServer(d *Daemon) *http.Server {
/* Setup the web server */
router := mux.NewRouter()
router.StrictSlash(false)
router.SkipClean(true)
router := http.NewServeMux()

router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
Expand All @@ -219,20 +212,18 @@ func metricsServer(d *Daemon) *http.Server {
d.createCmd(router, "1.0", api10Cmd)
d.createCmd(router, "1.0", metricsCmd)

router.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
notFoundHandler := func(w http.ResponseWriter, r *http.Request) {
logger.Info("Sending top level 404", logger.Ctx{"url": r.URL, "method": r.Method, "remote": r.RemoteAddr})
w.Header().Set("Content-Type", "application/json")
_ = response.NotFound(nil).Render(w)
})
}

return &http.Server{Handler: &httpServer{r: router, d: d}}
return &http.Server{Handler: &httpServer{r: router, d: d, n: notFoundHandler}}
}

func storageBucketsServer(d *Daemon) *http.Server {
/* Setup the web server */
router := mux.NewRouter()
router.StrictSlash(false)
router.SkipClean(true)
router := http.NewServeMux()

router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// Wait until daemon is fully started.
Expand Down Expand Up @@ -294,7 +285,7 @@ func storageBucketsServer(d *Daemon) *http.Server {
})

// We use the NotFoundHandler to reverse proxy requests to dynamically started local MinIO processes.
router.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
notFoundHandler := func(w http.ResponseWriter, r *http.Request) {
// Wait until daemon is fully started.
<-d.waitReady.Done()

Expand Down Expand Up @@ -364,14 +355,15 @@ func storageBucketsServer(d *Daemon) *http.Server {

rproxy := httputil.NewSingleHostReverseProxy(&u)
rproxy.ServeHTTP(w, r)
})
}

return &http.Server{Handler: &httpServer{r: router, d: d}}
return &http.Server{Handler: &httpServer{r: router, d: d, n: notFoundHandler}}
}

type httpServer struct {
r *mux.Router
r *http.ServeMux
d *Daemon
n func(w http.ResponseWriter, r *http.Request)
}

func (s *httpServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
Expand All @@ -390,6 +382,16 @@ func (s *httpServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
return
}

// Execute NotFound function if defined
if s.n != nil {
_, pattern := s.r.Handler(req)
// Empty pattern = no Handler for this request
if pattern == "" {
s.n(rw, req)
return
}
}

// Call the original server
s.r.ServeHTTP(rw, req)
}
Expand Down
3 changes: 0 additions & 3 deletions cmd/incusd/api_1.0.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,7 @@ var api10 = []APIEndpoint{
imageAliasCmd,
imageAliasesCmd,
imageCmd,
imageExportCmd,
imageRefreshCmd,
imagesCmd,
imageSecretCmd,
metadataConfigurationCmd,
networkCmd,
networkLeasesCmd,
Expand Down
16 changes: 7 additions & 9 deletions cmd/incusd/api_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ import (
"sync"
"time"

"github.com/gorilla/mux"

incus "github.com/lxc/incus/v6/client"
"github.com/lxc/incus/v6/internal/filter"
internalInstance "github.com/lxc/incus/v6/internal/instance"
Expand Down Expand Up @@ -1503,7 +1501,7 @@ func clusterNodesPost(d *Daemon, r *http.Request) response.Response {
func clusterNodeGet(d *Daemon, r *http.Request) response.Response {
s := d.State()

name, err := url.PathUnescape(mux.Vars(r)["name"])
name, err := url.PathUnescape(r.PathValue("name"))
if err != nil {
return response.SmartError(err)
}
Expand Down Expand Up @@ -1639,7 +1637,7 @@ func clusterNodePut(d *Daemon, r *http.Request) response.Response {

// updateClusterNode is shared between clusterNodePut and clusterNodePatch.
func updateClusterNode(s *state.State, gateway *cluster.Gateway, r *http.Request, isPatch bool) response.Response {
name, err := url.PathUnescape(mux.Vars(r)["name"])
name, err := url.PathUnescape(r.PathValue("name"))
if err != nil {
return response.SmartError(err)
}
Expand Down Expand Up @@ -1945,7 +1943,7 @@ func clusterValidateConfig(config map[string]string) error {
func clusterNodePost(d *Daemon, r *http.Request) response.Response {
s := d.State()

memberName, err := url.PathUnescape(mux.Vars(r)["name"])
memberName, err := url.PathUnescape(r.PathValue("name"))
if err != nil {
return response.SmartError(err)
}
Expand Down Expand Up @@ -2022,7 +2020,7 @@ func clusterNodeDelete(d *Daemon, r *http.Request) response.Response {
pending = 0
}

name, err := url.PathUnescape(mux.Vars(r)["name"])
name, err := url.PathUnescape(r.PathValue("name"))
if err != nil {
return response.SmartError(err)
}
Expand Down Expand Up @@ -2801,7 +2799,7 @@ func clusterCheckNetworksMatch(ctx context.Context, clusterDB *db.Cluster, reqNe
func internalClusterRaftNodeDelete(d *Daemon, r *http.Request) response.Response {
s := d.State()

address, err := url.PathUnescape(mux.Vars(r)["address"])
address, err := url.PathUnescape(r.PathValue("address"))
if err != nil {
return response.SmartError(err)
}
Expand Down Expand Up @@ -2854,7 +2852,7 @@ func internalClusterRaftNodeDelete(d *Daemon, r *http.Request) response.Response
// "500":
// $ref: "#/responses/InternalServerError"
func clusterNodeStateGet(d *Daemon, r *http.Request) response.Response {
memberName, err := url.PathUnescape(mux.Vars(r)["name"])
memberName, err := url.PathUnescape(r.PathValue("name"))
if err != nil {
return response.SmartError(err)
}
Expand Down Expand Up @@ -2903,7 +2901,7 @@ func clusterNodeStateGet(d *Daemon, r *http.Request) response.Response {
// "500":
// $ref: "#/responses/InternalServerError"
func clusterNodeStatePost(d *Daemon, r *http.Request) response.Response {
name, err := url.PathUnescape(mux.Vars(r)["name"])
name, err := url.PathUnescape(r.PathValue("name"))
if err != nil {
return response.SmartError(err)
}
Expand Down
4 changes: 1 addition & 3 deletions cmd/incusd/api_cluster_evacuation.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import (
"strings"
"time"

"github.com/gorilla/mux"

"golang.org/x/sync/errgroup"

incus "github.com/lxc/incus/v6/client"
Expand Down Expand Up @@ -261,7 +259,7 @@ func evacuateInstancesFunc(ctx context.Context, inst instance.Instance, opts eva
func restoreClusterMember(d *Daemon, r *http.Request) response.Response {
s := d.State()

originName, err := url.PathUnescape(mux.Vars(r)["name"])
originName, err := url.PathUnescape(r.PathValue("name"))
if err != nil {
return response.SmartError(err)
}
Expand Down
12 changes: 5 additions & 7 deletions cmd/incusd/api_cluster_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import (
"slices"
"strings"

"github.com/gorilla/mux"

"github.com/lxc/incus/v6/internal/server/auth"
"github.com/lxc/incus/v6/internal/server/db"
dbCluster "github.com/lxc/incus/v6/internal/server/db/cluster"
Expand Down Expand Up @@ -317,7 +315,7 @@ func clusterGroupsGet(d *Daemon, r *http.Request) response.Response {
func clusterGroupGet(d *Daemon, r *http.Request) response.Response {
s := d.State()

name, err := url.PathUnescape(mux.Vars(r)["name"])
name, err := url.PathUnescape(r.PathValue("name"))
if err != nil {
return response.SmartError(err)
}
Expand Down Expand Up @@ -393,7 +391,7 @@ func clusterGroupGet(d *Daemon, r *http.Request) response.Response {
func clusterGroupPost(d *Daemon, r *http.Request) response.Response {
s := d.State()

name, err := url.PathUnescape(mux.Vars(r)["name"])
name, err := url.PathUnescape(r.PathValue("name"))
if err != nil {
return response.SmartError(err)
}
Expand Down Expand Up @@ -490,7 +488,7 @@ func clusterGroupPost(d *Daemon, r *http.Request) response.Response {
func clusterGroupPut(d *Daemon, r *http.Request) response.Response {
s := d.State()

name, err := url.PathUnescape(mux.Vars(r)["name"])
name, err := url.PathUnescape(r.PathValue("name"))
if err != nil {
return response.SmartError(err)
}
Expand Down Expand Up @@ -661,7 +659,7 @@ func clusterGroupPut(d *Daemon, r *http.Request) response.Response {
func clusterGroupPatch(d *Daemon, r *http.Request) response.Response {
s := d.State()

name, err := url.PathUnescape(mux.Vars(r)["name"])
name, err := url.PathUnescape(r.PathValue("name"))
if err != nil {
return response.SmartError(err)
}
Expand Down Expand Up @@ -861,7 +859,7 @@ func clusterGroupPatch(d *Daemon, r *http.Request) response.Response {
func clusterGroupDelete(d *Daemon, r *http.Request) response.Response {
s := d.State()

name, err := url.PathUnescape(mux.Vars(r)["name"])
name, err := url.PathUnescape(r.PathValue("name"))
if err != nil {
return response.SmartError(err)
}
Expand Down
5 changes: 2 additions & 3 deletions cmd/incusd/api_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"strconv"
"strings"

"github.com/gorilla/mux"
"golang.org/x/sys/unix"

internalInstance "github.com/lxc/incus/v6/internal/instance"
Expand Down Expand Up @@ -338,7 +337,7 @@ func internalShutdown(d *Daemon, r *http.Request) response.Response {
// It detects whether the instance reference is an instance ID or instance name and loads instance accordingly.
func internalContainerHookLoadFromReference(s *state.State, r *http.Request) (instance.Instance, error) {
var inst instance.Instance
instanceRef, err := url.PathUnescape(mux.Vars(r)["instanceRef"])
instanceRef, err := url.PathUnescape(r.PathValue("instanceRef"))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -455,7 +454,7 @@ func internalVirtualMachineOnResize(d *Daemon, r *http.Request) response.Respons
s := d.State()

// Get the instance ID.
instanceID, err := strconv.Atoi(mux.Vars(r)["instanceRef"])
instanceID, err := strconv.Atoi(r.PathValue("instanceRef"))
if err != nil {
return response.BadRequest(err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/incusd/api_os.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
)

var apiOS = APIEndpoint{
Path: "{name:.*}",
Path: "{name...}",
Patch: APIEndpointAction{Handler: apiOSProxy, AccessHandler: allowPermission(auth.ObjectTypeServer, auth.EntitlementCanEdit)},
Put: APIEndpointAction{Handler: apiOSProxy, AccessHandler: allowPermission(auth.ObjectTypeServer, auth.EntitlementCanEdit)},
Get: APIEndpointAction{Handler: apiOSProxy, AccessHandler: allowPermission(auth.ObjectTypeServer, auth.EntitlementCanEdit)},
Expand Down
16 changes: 7 additions & 9 deletions cmd/incusd/api_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import (
"slices"
"strings"

"github.com/gorilla/mux"

incus "github.com/lxc/incus/v6/client"
"github.com/lxc/incus/v6/internal/filter"
"github.com/lxc/incus/v6/internal/jmap"
Expand Down Expand Up @@ -476,7 +474,7 @@ func projectCreateDefaultProfile(ctx context.Context, tx *db.ClusterTx, project
func projectGet(d *Daemon, r *http.Request) response.Response {
s := d.State()

name, err := url.PathUnescape(mux.Vars(r)["name"])
name, err := url.PathUnescape(r.PathValue("name"))
if err != nil {
return response.SmartError(err)
}
Expand Down Expand Up @@ -541,7 +539,7 @@ func projectGet(d *Daemon, r *http.Request) response.Response {
func projectPut(d *Daemon, r *http.Request) response.Response {
s := d.State()

name, err := url.PathUnescape(mux.Vars(r)["name"])
name, err := url.PathUnescape(r.PathValue("name"))
if err != nil {
return response.SmartError(err)
}
Expand Down Expand Up @@ -627,7 +625,7 @@ func projectPut(d *Daemon, r *http.Request) response.Response {
func projectPatch(d *Daemon, r *http.Request) response.Response {
s := d.State()

name, err := url.PathUnescape(mux.Vars(r)["name"])
name, err := url.PathUnescape(r.PathValue("name"))
if err != nil {
return response.SmartError(err)
}
Expand Down Expand Up @@ -843,7 +841,7 @@ func projectChange(ctx context.Context, s *state.State, project *api.Project, re
func projectPost(d *Daemon, r *http.Request) response.Response {
s := d.State()

name, err := url.PathUnescape(mux.Vars(r)["name"])
name, err := url.PathUnescape(r.PathValue("name"))
if err != nil {
return response.SmartError(err)
}
Expand Down Expand Up @@ -954,7 +952,7 @@ func projectPost(d *Daemon, r *http.Request) response.Response {
func projectDelete(d *Daemon, r *http.Request) response.Response {
s := d.State()

name, err := url.PathUnescape(mux.Vars(r)["name"])
name, err := url.PathUnescape(r.PathValue("name"))
if err != nil {
return response.SmartError(err)
}
Expand Down Expand Up @@ -1310,7 +1308,7 @@ func projectDelete(d *Daemon, r *http.Request) response.Response {
func projectStateGet(d *Daemon, r *http.Request) response.Response {
s := d.State()

name, err := url.PathUnescape(mux.Vars(r)["name"])
name, err := url.PathUnescape(r.PathValue("name"))
if err != nil {
return response.SmartError(err)
}
Expand Down Expand Up @@ -1985,7 +1983,7 @@ func projectValidateRestrictedSubnets(s *state.State, value string) error {
func projectAccess(d *Daemon, r *http.Request) response.Response {
s := d.State()

name, err := url.PathUnescape(mux.Vars(r)["name"])
name, err := url.PathUnescape(r.PathValue("name"))
if err != nil {
return response.SmartError(err)
}
Expand Down
Loading
Loading