From 978519785eb769e57b262dd9ef13037c5137a090 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Thu, 30 Jun 2022 16:14:41 +0200 Subject: [PATCH] Extract struct splitMux --- lib/api/api.go | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/lib/api/api.go b/lib/api/api.go index 7e5a640fa56..7e7ff5dd477 100644 --- a/lib/api/api.go +++ b/lib/api/api.go @@ -368,22 +368,23 @@ func (s *service) Serve(ctx context.Context) error { } // The main routing handler - unauthenticatedMux := http.NewServeMux() - mux.Handle("/rest/", noCacheRestMux) - unauthenticatedMux.Handle("/rest/", handler) - mux.HandleFunc("/qr/", s.getQR) - unauthenticatedMux.Handle("/qr/", handler) + mainMuxBuilder := splitMux{ + fallbackHandler: &handler, + fallbackMux: mux, // Authenticated section + mainMux: http.NewServeMux(), // Unauthenticated section + } + mainMuxBuilder.Handle("/rest/", noCacheRestMux) + mainMuxBuilder.HandleFunc("/qr/", s.getQR) // Handle the special meta.js path - mux.HandleFunc("/meta.js", s.getJSMetadata) - unauthenticatedMux.Handle("/meta.js", handler) + mainMuxBuilder.HandleFunc("/meta.js", s.getJSMetadata) // Serve compiled in assets unless an asset directory was set (for development) - unauthenticatedMux.Handle("/", s.statics) + mainMuxBuilder.mainMux.Handle("/", s.statics) srv := http.Server{ // Redirect to HTTPS if we are supposed to - Handler: debugMiddleware(redirectToHTTPSMiddleware(guiCfg.UseTLS(), unauthenticatedMux)), + Handler: debugMiddleware(redirectToHTTPSMiddleware(guiCfg.UseTLS(), mainMuxBuilder.mainMux)), // ReadTimeout must be longer than SyncthingController $scope.refresh // interval to avoid HTTP keepalive/GUI refresh race. ReadTimeout: 15 * time.Second, @@ -446,6 +447,27 @@ func (s *service) Serve(ctx context.Context) error { return err } +// The purpose of splitMux is to help have an unauthenticated section of the API +// and have everything else fall back to the authenticated segment. +// The Handle and HandleFunc methods here let you call a "handle" function once +// but have the path set up in both the unauthenticated "top" mux and the fallback mux. +// The fallbackHandler is also needed since the fallbackHandler wraps the fallbackMux, +// but routing paths are registered in the fallbackMux, +// and the mainMux needs to be configured with the same paths. +type splitMux struct { + fallbackHandler *http.Handler + fallbackMux *http.ServeMux + mainMux *http.ServeMux +} +func (s *splitMux) Handle(path string, handler http.Handler) { + s.fallbackMux.Handle(path, handler) + s.mainMux.Handle(path, *s.fallbackHandler) +} +func (s *splitMux) HandleFunc(path string, handler http.HandlerFunc) { + s.fallbackMux.Handle(path, handler) + s.mainMux.Handle(path, *s.fallbackHandler) +} + // Complete implements suture.IsCompletable, which signifies to the supervisor // whether to stop restarting the service. func (s *service) Complete() bool {