github.com/decred/politeia@v1.4.0/politeiad/middleware.go (about)

     1  // Copyright (c) 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  	v2 "github.com/decred/politeia/politeiad/api/v2"
    15  	"github.com/decred/politeia/util"
    16  )
    17  
    18  // closeBodyMiddleware closes the request body.
    19  func closeBodyMiddleware(next http.Handler) http.Handler {
    20  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    21  		next.ServeHTTP(w, r)
    22  		r.Body.Close()
    23  	})
    24  }
    25  
    26  // loggingMiddleware logs all incoming commands before calling the next
    27  // function.
    28  func loggingMiddleware(next http.Handler) http.Handler {
    29  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    30  		// Trace incoming request
    31  		log.Tracef("%v", newLogClosure(func() string {
    32  			trace, err := httputil.DumpRequest(r, true)
    33  			if err != nil {
    34  				trace = []byte(fmt.Sprintf("logging: "+
    35  					"DumpRequest %v", err))
    36  			}
    37  			return string(trace)
    38  		}))
    39  
    40  		// Log incoming connection
    41  		log.Infof("%v %v %v %v", util.RemoteAddr(r), r.Method, r.URL, r.Proto)
    42  
    43  		// Call next handler
    44  		next.ServeHTTP(w, r)
    45  	})
    46  }
    47  
    48  // recoverMiddleware recovers from any panics by logging the panic and
    49  // returning a 500 response.
    50  func recoverMiddleware(next http.Handler) http.Handler {
    51  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    52  		// Defer the function so that it gets executed when the request
    53  		// is being closed out, not when its being opened.
    54  		defer func() {
    55  			if err := recover(); err != nil {
    56  				errorCode := time.Now().Unix()
    57  				log.Criticalf("%v %v %v %v Internal error %v: %v",
    58  					util.RemoteAddr(r), r.Method, r.URL, r.Proto, errorCode, err)
    59  
    60  				log.Criticalf("Stacktrace (THIS IS AN ACTUAL PANIC): %s",
    61  					debug.Stack())
    62  
    63  				util.RespondWithJSON(w, http.StatusInternalServerError,
    64  					v2.ServerErrorReply{
    65  						ErrorCode: errorCode,
    66  					})
    67  			}
    68  		}()
    69  
    70  		next.ServeHTTP(w, r)
    71  	})
    72  }
    73  
    74  // middleware contains the middleware that use configurable settings.
    75  type middleware struct {
    76  	reqBodySizeLimit int64 // In bytes
    77  }
    78  
    79  // reqBodySizeLimitMiddleware applies a maximum request body size limit to
    80  // requests.
    81  //
    82  // NOTE: This will only cause an error if the request body is read by the
    83  // request handler, e.g. the JSON from a POST request is decoded into a struct.
    84  func (m *middleware) reqBodySizeLimitMiddleware(next http.Handler) http.Handler {
    85  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    86  		log.Tracef("Applying a max body size of %v bytes to the request body",
    87  			m.reqBodySizeLimit)
    88  
    89  		r.Body = http.MaxBytesReader(w, r.Body, m.reqBodySizeLimit)
    90  		next.ServeHTTP(w, r)
    91  	})
    92  }