Commit 4d9741dd authored by Matthew Holt's avatar Matthew Holt

pprof: Only handle if path matches /debug/pprof, add tests

parent a05a664d
...@@ -20,7 +20,8 @@ func PProf(c *Controller) (middleware.Middleware, error) { ...@@ -20,7 +20,8 @@ func PProf(c *Controller) (middleware.Middleware, error) {
} }
found = true found = true
} }
return func(next middleware.Handler) middleware.Handler { return func(next middleware.Handler) middleware.Handler {
return pprof.New(next) return &pprof.Handler{Next: next, Mux: pprof.NewMux()}
}, nil }, nil
} }
CHANGES CHANGES
<master> <master>
- New pprof directive for exposing process performance profile
- Toggle case-sensitive path matching with environment variable
- proxy: New max_conns setting to limit max connections per upstream - proxy: New max_conns setting to limit max connections per upstream
- Internal improvements, restructuring, and bug fixes - Internal improvements, restructuring, and bug fixes
......
...@@ -7,28 +7,35 @@ import ( ...@@ -7,28 +7,35 @@ import (
"github.com/mholt/caddy/middleware" "github.com/mholt/caddy/middleware"
) )
//Handler is a simple struct whose ServeHTTP will delegate relevant pprof endpoints to net/http/pprof // BasePath is the base path to match for all pprof requests.
type handler struct { const BasePath = "/debug/pprof"
mux *http.ServeMux
// Handler is a simple struct whose ServeHTTP will delegate pprof
// endpoints to their equivalent net/http/pprof handlers.
type Handler struct {
Next middleware.Handler
Mux *http.ServeMux
} }
//New creates a new pprof middleware // ServeHTTP handles requests to BasePath with pprof, or passes
func New(next middleware.Handler) middleware.Handler { // all other requests up the chain.
//pretty much copying what pprof does on init: https://golang.org/src/net/http/pprof/pprof.go#L67 func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
mux := http.NewServeMux() if middleware.Path(r.URL.Path).Matches(BasePath) {
mux.HandleFunc("/debug/pprof/", pp.Index) h.Mux.ServeHTTP(w, r)
mux.HandleFunc("/debug/pprof/cmdline", pp.Cmdline) return 0, nil
mux.HandleFunc("/debug/pprof/profile", pp.Profile) }
mux.HandleFunc("/debug/pprof/symbol", pp.Symbol) return h.Next.ServeHTTP(w, r)
mux.HandleFunc("/debug/pprof/trace", pp.Trace)
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
next.ServeHTTP(w, r)
})
return &handler{mux}
} }
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { // NewMux returns a new http.ServeMux that routes pprof requests.
rec := middleware.NewResponseRecorder(w) // It pretty much copies what the std lib pprof does on init:
h.mux.ServeHTTP(rec, r) // https://golang.org/src/net/http/pprof/pprof.go#L67
return rec.Status(), nil func NewMux() *http.ServeMux {
mux := http.NewServeMux()
mux.HandleFunc(BasePath+"/", pp.Index)
mux.HandleFunc(BasePath+"/cmdline", pp.Cmdline)
mux.HandleFunc(BasePath+"/profile", pp.Profile)
mux.HandleFunc(BasePath+"/symbol", pp.Symbol)
mux.HandleFunc(BasePath+"/trace", pp.Trace)
return mux
} }
package pprof
import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/mholt/caddy/middleware"
)
func TestServeHTTP(t *testing.T) {
h := Handler{
Next: middleware.HandlerFunc(nextHandler),
Mux: NewMux(),
}
w := httptest.NewRecorder()
r, err := http.NewRequest("GET", "/debug/pprof", nil)
if err != nil {
t.Fatal(err)
}
status, err := h.ServeHTTP(w, r)
if status != 0 {
t.Errorf("Expected status %d but got %d", 0, status)
}
if err != nil {
t.Errorf("Expected nil error, but got: %v", err)
}
if w.Body.String() == "content" {
t.Errorf("Expected pprof to handle request, but it didn't")
}
w = httptest.NewRecorder()
r, err = http.NewRequest("GET", "/foo", nil)
if err != nil {
t.Fatal(err)
}
status, err = h.ServeHTTP(w, r)
if status != http.StatusNotFound {
t.Errorf("Test two: Expected status %d but got %d", http.StatusNotFound, status)
}
if err != nil {
t.Errorf("Test two: Expected nil error, but got: %v", err)
}
if w.Body.String() != "content" {
t.Errorf("Expected pprof to pass the request thru, but it didn't; got: %s", w.Body.String())
}
}
func nextHandler(w http.ResponseWriter, r *http.Request) (int, error) {
fmt.Fprintf(w, "content")
return http.StatusNotFound, nil
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment