github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/api/middleware.go (about) 1 package api 2 3 import ( 4 "fmt" 5 "net/http" 6 "time" 7 8 "github.com/gorilla/mux" 9 "github.com/qri-io/qri/api/util" 10 "github.com/qri-io/qri/dsref" 11 ) 12 13 // Middleware handles request logging 14 func (s Server) Middleware(handler http.HandlerFunc) http.HandlerFunc { 15 return s.mwFunc(handler, true) 16 } 17 18 // NoLogMiddleware runs middleware without logging the request 19 func (s Server) NoLogMiddleware(handler http.HandlerFunc) http.HandlerFunc { 20 return s.mwFunc(handler, false) 21 } 22 23 func (s Server) mwFunc(handler http.HandlerFunc, shouldLog bool) http.HandlerFunc { 24 return func(w http.ResponseWriter, r *http.Request) { 25 if shouldLog { 26 log.Infof("%s %s %s", r.Method, r.URL.Path, time.Now()) 27 } 28 29 handler.ServeHTTP(w, r) 30 } 31 } 32 33 // corsMiddleware adds Cross-Origin Resource Sharing headers for any request 34 // who's origin matches one of allowedOrigins 35 func corsMiddleware(allowedOrigins []string) mux.MiddlewareFunc { 36 return func(next http.Handler) http.Handler { 37 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 38 origin := r.Header.Get("Origin") 39 for _, o := range allowedOrigins { 40 if origin == o { 41 w.Header().Set("Access-Control-Allow-Origin", origin) 42 w.Header().Set("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS") 43 w.Header().Set("Access-Control-Allow-Headers", "Content-Type,Authorization") 44 w.Header().Set("Access-Control-Allow-Credentials", "true") 45 } 46 } 47 48 // intercept OPTIONS requests with an early return 49 if r.Method == http.MethodOptions { 50 util.EmptyOkHandler(w, r) 51 return 52 } 53 54 next.ServeHTTP(w, r) 55 }) 56 } 57 } 58 59 // muxVarsToQueryParamMiddleware moves all mux variables to query parameter 60 // values, failing with an error if a name collision with user-provided query 61 // params occurs 62 func muxVarsToQueryParamMiddleware(next http.Handler) http.Handler { 63 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 64 if err := setMuxVarsToQueryParams(r); err != nil { 65 util.WriteErrResponse(w, http.StatusBadRequest, err) 66 return 67 } 68 next.ServeHTTP(w, r) 69 }) 70 } 71 72 func setMuxVarsToQueryParams(r *http.Request) error { 73 q := r.URL.Query() 74 for varName, val := range mux.Vars(r) { 75 if q.Get(varName) != "" { 76 return fmt.Errorf("conflict in query param: %s = %s", varName, val) 77 } 78 q.Add(varName, val) 79 } 80 r.URL.RawQuery = q.Encode() 81 return nil 82 } 83 84 // refStringMiddleware converts gorilla mux params to a "refstr" query parmeter 85 // and adds it to an http request 86 func refStringMiddleware(next http.Handler) http.Handler { 87 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 88 setRefStringFromMuxVars(r) 89 next.ServeHTTP(w, r) 90 }) 91 } 92 93 func setRefStringFromMuxVars(r *http.Request) { 94 mvars := mux.Vars(r) 95 ref := dsref.Ref{ 96 Username: mvars["username"], 97 Name: mvars["name"], 98 Path: muxVarsPath(mvars), 99 } 100 101 if refstr := ref.String(); refstr != "" { 102 q := r.URL.Query() 103 q.Add("ref", refstr) 104 r.URL.RawQuery = q.Encode() 105 } 106 } 107 108 func muxVarsPath(mvars map[string]string) string { 109 fs := mvars["fs"] 110 hash := mvars["hash"] 111 if fs != "" && hash != "" { 112 return fmt.Sprintf("/%s/%s", fs, hash) 113 } 114 return "" 115 }