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  }