summaryrefslogtreecommitdiff
path: root/internal/router
diff options
context:
space:
mode:
authorLibravatar kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com>2022-04-28 13:32:53 +0100
committerLibravatar GitHub <noreply@github.com>2022-04-28 13:32:53 +0100
commit69011d4901a042a9fba3d6d71061c25d20a9ecdc (patch)
tree6cbd14ba41eddfe9c223542467dce95824664bad /internal/router
parentreplace async client API / federator msg processing with worker pools (#497) (diff)
downloadgotosocial-69011d4901a042a9fba3d6d71061c25d20a9ecdc.tar.xz
Add support for running profiling when debug build-tags provided (#491)
* wrap root HTTP handler in debug.WithPprof(), rearrange router.Start() to support this * remove unused code * set debug buildtag in build script when $DEBUG set * update go-debug version with fixed handler * use clone of router.srv for LE cert manager, reset server timeouts in debug * add kim's other libraries to README
Diffstat (limited to 'internal/router')
-rw-r--r--internal/router/router.go92
1 files changed, 57 insertions, 35 deletions
diff --git a/internal/router/router.go b/internal/router/router.go
index 57e0d36b2..0367ba912 100644
--- a/internal/router/router.go
+++ b/internal/router/router.go
@@ -24,6 +24,7 @@ import (
"net/http"
"time"
+ "codeberg.org/gruf/go-debug"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
@@ -32,7 +33,7 @@ import (
"golang.org/x/crypto/acme/autocert"
)
-var (
+const (
readTimeout = 60 * time.Second
writeTimeout = 30 * time.Second
idleTimeout = 30 * time.Second
@@ -69,38 +70,69 @@ func (r *router) AttachStaticFS(relativePath string, fs http.FileSystem) {
// Start starts the router nicely. It will serve two handlers if letsencrypt is enabled, and only the web/API handler if letsencrypt is not enabled.
func (r *router) Start() {
- keys := config.Keys
- leEnabled := viper.GetBool(keys.LetsEncryptEnabled)
+ var (
+ keys = config.Keys
+
+ // listen is the server start function, by
+ // default pointing to regular HTTP listener,
+ // but updated to TLS if LetsEncrypt is enabled.
+ listen = r.srv.ListenAndServe
+ )
+
+ if viper.GetBool(keys.LetsEncryptEnabled) {
+ // LetsEncrypt support is enabled
+
+ // Prepare an HTTPS-redirect handler for LetsEncrypt fallback
+ redirect := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
+ target := "https://" + r.Host + r.URL.Path
+ if len(r.URL.RawQuery) > 0 {
+ target += "?" + r.URL.RawQuery
+ }
+ http.Redirect(rw, r, target, http.StatusTemporaryRedirect)
+ })
- if leEnabled {
- bindAddress := viper.GetString(keys.BindAddress)
- lePort := viper.GetInt(keys.LetsEncryptPort)
+ // Clone HTTP server but with autocert handler
+ srv := r.srv
+ srv.Handler = r.certManager.HTTPHandler(redirect)
- // serve the http handler on the selected letsencrypt port, for receiving letsencrypt requests and solving their devious riddles
+ // Start the LetsEncrypt autocert manager HTTP server.
go func() {
- listen := fmt.Sprintf("%s:%d", bindAddress, lePort)
- logrus.Infof("letsencrypt listening on %s", listen)
- if err := http.ListenAndServe(listen, r.certManager.HTTPHandler(http.HandlerFunc(httpsRedirect))); err != nil && err != http.ErrServerClosed {
+ addr := fmt.Sprintf("%s:%d",
+ viper.GetString(keys.BindAddress),
+ viper.GetInt(keys.LetsEncryptPort),
+ )
+
+ logrus.Infof("letsencrypt listening on %s", addr)
+
+ if err := srv.ListenAndServe(); err != nil &&
+ err != http.ErrServerClosed {
logrus.Fatalf("letsencrypt: listen: %s", err)
}
}()
- // and serve the actual TLS handler
- go func() {
- logrus.Infof("listening on %s", r.srv.Addr)
- if err := r.srv.ListenAndServeTLS("", ""); err != nil && err != http.ErrServerClosed {
- logrus.Fatalf("listen: %s", err)
- }
- }()
- } else {
- // no tls required
- go func() {
- logrus.Infof("listening on %s", r.srv.Addr)
- if err := r.srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
- logrus.Fatalf("listen: %s", err)
- }
- }()
+ // TLS is enabled, update the listen function
+ listen = func() error { return r.srv.ListenAndServeTLS("", "") }
+ }
+
+ // Pass the server handler through a debug pprof middleware handler.
+ // For standard production builds this will be a no-op, but when the
+ // "debug" or "debugenv" build-tag is set pprof stats will be served
+ // at the standard "/debug/pprof" URL.
+ r.srv.Handler = debug.WithPprof(r.srv.Handler)
+ if debug.DEBUG() {
+ // Profiling requires timeouts longer than 30s, so reset these.
+ logrus.Warn("resetting http.Server{} timeout to support profiling")
+ r.srv.ReadTimeout = 0
+ r.srv.WriteTimeout = 0
}
+
+ // Start the main listener.
+ go func() {
+ logrus.Infof("listening on %s", r.srv.Addr)
+ if err := listen(); err != nil && err != http.ErrServerClosed {
+ logrus.Fatalf("listen: %s", err)
+ }
+ }()
}
// Stop shuts down the router nicely
@@ -193,13 +225,3 @@ func New(ctx context.Context, db db.DB) (Router, error) {
certManager: m,
}, nil
}
-
-func httpsRedirect(w http.ResponseWriter, req *http.Request) {
- target := "https://" + req.Host + req.URL.Path
-
- if len(req.URL.RawQuery) > 0 {
- target += "?" + req.URL.RawQuery
- }
-
- http.Redirect(w, req, target, http.StatusTemporaryRedirect)
-}