github.com/decred/politeia@v1.4.0/politeiawww/middleware.go (about) 1 // Copyright (c) 2017-2021 The Decred developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "fmt" 9 "net/http" 10 "net/http/httputil" 11 "runtime/debug" 12 "time" 13 14 www "github.com/decred/politeia/politeiawww/api/www/v1" 15 "github.com/decred/politeia/politeiawww/logger" 16 "github.com/decred/politeia/util" 17 ) 18 19 // closeBodyMiddleware closes the request body. 20 func closeBodyMiddleware(next http.Handler) http.Handler { 21 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 22 next.ServeHTTP(w, r) 23 r.Body.Close() 24 }) 25 } 26 27 // loggingMiddleware logs all incoming commands before calling the next 28 // function. 29 // 30 // NOTE: LOGGING WILL LOG PASSWORDS IF TRACING IS ENABLED. 31 func loggingMiddleware(next http.Handler) http.Handler { 32 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 33 // Trace incoming request 34 log.Tracef("%v", logger.NewLogClosure(func() string { 35 trace, err := httputil.DumpRequest(r, true) 36 if err != nil { 37 trace = []byte(fmt.Sprintf("logging: "+ 38 "DumpRequest %v", err)) 39 } 40 return string(trace) 41 })) 42 43 // Log incoming connection 44 log.Infof("%v %v %v %v", util.RemoteAddr(r), r.Method, r.URL, r.Proto) 45 46 // Call next handler 47 next.ServeHTTP(w, r) 48 }) 49 } 50 51 // recoverMiddleware recovers from any panics by logging the panic and 52 // returning a 500 response. 53 func recoverMiddleware(next http.Handler) http.Handler { 54 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 55 // Defer the function so that it gets executed when the request 56 // is being closed out, not when its being opened. 57 defer func() { 58 if err := recover(); err != nil { 59 errorCode := time.Now().Unix() 60 log.Criticalf("%v %v %v %v Internal error %v: %v", 61 util.RemoteAddr(r), r.Method, r.URL, r.Proto, errorCode, err) 62 63 log.Criticalf("Stacktrace (THIS IS AN ACTUAL PANIC): %s", 64 debug.Stack()) 65 66 util.RespondWithJSON(w, http.StatusInternalServerError, 67 www.ErrorReply{ 68 ErrorCode: errorCode, 69 }) 70 } 71 }() 72 73 next.ServeHTTP(w, r) 74 }) 75 } 76 77 // middleware contains the middleware that use configurable settings. 78 type middleware struct { 79 reqBodySizeLimit int64 // In bytes 80 } 81 82 // reqBodySizeLimitMiddleware applies a maximum request body size limit to 83 // requests. 84 // 85 // NOTE: This will only cause an error if the request body is read by the 86 // request handler, e.g. the JSON from a POST request is decoded into a struct. 87 func (m *middleware) reqBodySizeLimitMiddleware(next http.Handler) http.Handler { 88 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 89 log.Tracef("Applying a max body size of %v bytes to the request body", 90 m.reqBodySizeLimit) 91 92 r.Body = http.MaxBytesReader(w, r.Body, m.reqBodySizeLimit) 93 next.ServeHTTP(w, r) 94 }) 95 }