github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/pkg/api/server/handler_api.go (about)

     1  package server
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net/http"
     7  	"runtime"
     8  
     9  	"github.com/containers/podman/v2/pkg/api/handlers/utils"
    10  	"github.com/containers/podman/v2/pkg/auth"
    11  	"github.com/google/uuid"
    12  	"github.com/sirupsen/logrus"
    13  )
    14  
    15  // APIHandler is a wrapper to enhance HandlerFunc's and remove redundant code
    16  func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
    17  	return func(w http.ResponseWriter, r *http.Request) {
    18  		// http.Server hides panics, we want to see them and fix the cause.
    19  		defer func() {
    20  			err := recover()
    21  			if err != nil {
    22  				buf := make([]byte, 1<<20)
    23  				n := runtime.Stack(buf, true)
    24  				logrus.Warnf("Recovering from API handler panic: %v, %s", err, buf[:n])
    25  				// Try to inform client things went south... won't work if handler already started writing response body
    26  				utils.InternalServerError(w, fmt.Errorf("%v", err))
    27  			}
    28  		}()
    29  
    30  		// Wrapper to hide some boiler plate
    31  		fn := func(w http.ResponseWriter, r *http.Request) {
    32  			rid := uuid.New().String()
    33  			logrus.Infof("APIHandler(%s) -- %s %s BEGIN", rid, r.Method, r.URL.String())
    34  			if logrus.IsLevelEnabled(logrus.DebugLevel) {
    35  				for k, v := range r.Header {
    36  					switch auth.HeaderAuthName(k) {
    37  					case auth.XRegistryConfigHeader, auth.XRegistryAuthHeader:
    38  						logrus.Debugf("APIHandler(%s) -- Header: %s=<hidden>", rid, k)
    39  					default:
    40  						logrus.Debugf("APIHandler(%s) -- Header: %s=%v", rid, k, v)
    41  					}
    42  				}
    43  			}
    44  			// Set in case handler wishes to correlate logging events
    45  			r.Header.Set("X-Reference-Id", rid)
    46  
    47  			if err := r.ParseForm(); err != nil {
    48  				logrus.Infof("Failed Request: unable to parse form: %q (%s)", err, rid)
    49  			}
    50  
    51  			// TODO: Use r.ConnContext when ported to go 1.13
    52  			c := context.WithValue(r.Context(), "decoder", s.Decoder) // nolint
    53  			c = context.WithValue(c, "runtime", s.Runtime)            // nolint
    54  			c = context.WithValue(c, "shutdownFunc", s.Shutdown)      // nolint
    55  			c = context.WithValue(c, "idletracker", s.idleTracker)    // nolint
    56  			r = r.WithContext(c)
    57  
    58  			cv := utils.APIVersion[utils.CompatTree][utils.CurrentAPIVersion]
    59  			w.Header().Set("API-Version", fmt.Sprintf("%d.%d", cv.Major, cv.Minor))
    60  
    61  			lv := utils.APIVersion[utils.LibpodTree][utils.CurrentAPIVersion].String()
    62  			w.Header().Set("Libpod-API-Version", lv)
    63  			w.Header().Set("Server", "Libpod/"+lv+" ("+runtime.GOOS+")")
    64  
    65  			h(w, r)
    66  			logrus.Debugf("APIHandler(%s) -- %s %s END", rid, r.Method, r.URL.String())
    67  		}
    68  		fn(w, r)
    69  	}
    70  }
    71  
    72  // VersionedPath prepends the version parsing code
    73  // any handler may override this default when registering URL(s)
    74  func VersionedPath(p string) string {
    75  	return "/v{version:[0-9][0-9.]*}" + p
    76  }