Skip to content

Commit

Permalink
fix(api): handle OPTIONS requests on refRoute handlers
Browse files Browse the repository at this point in the history
  • Loading branch information
b5 committed Mar 17, 2021
1 parent 8ace963 commit 395d5ae
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 20 deletions.
11 changes: 11 additions & 0 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,16 @@ func handleRefRoute(m *mux.Router, p refRouteParams, f http.HandlerFunc) {

for _, route := range routes {
if len(p.Methods) > 0 {
hasOptions := false
for _, o := range p.Methods {
if o == http.MethodOptions {
hasOptions = true
break
}
}
if !hasOptions {
p.Methods = append(p.Methods, http.MethodOptions)
}
// TODO(b5): this is a band-aid that lets us punt on teaching lib about how to
// switch on HTTP verbs. I think we should use tricks like this that leverage
// the gorilla/mux package until we get a better sense of how our API uses
Expand All @@ -202,6 +212,7 @@ func NewServerRoutes(s Server) *mux.Router {
if m == nil {
m = mux.NewRouter()
}
m.Use(corsMiddleware(cfg.API.AllowedOrigins))
m.Use(muxVarsToQueryParamMiddleware)
m.Use(refStringMiddleware)
m.Use(token.OAuthTokenMiddleware)
Expand Down
46 changes: 26 additions & 20 deletions api/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,6 @@ func (s Server) mwFunc(handler http.HandlerFunc, shouldLog bool) http.HandlerFun
log.Infof("%s %s %s", r.Method, r.URL.Path, time.Now())
}

s.addCORSHeaders(w, r)
if r.Method == http.MethodOptions {
util.EmptyOkHandler(w, r)
return
}

if ok := s.readOnlyCheck(r); ok {
handler(w, r)
} else {
Expand All @@ -40,24 +34,36 @@ func (s Server) mwFunc(handler http.HandlerFunc, shouldLog bool) http.HandlerFun
}
}

func (s *Server) readOnlyCheck(r *http.Request) bool {
return !s.GetConfig().API.ReadOnly || r.Method == "GET" || r.Method == "OPTIONS"
}
// corsMiddleware adds Cross-Origin Resource Sharing headers for any request
// who's origin matches one of allowedOrigins
func corsMiddleware(allowedOrigins []string) mux.MiddlewareFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
origin := r.Header.Get("Origin")
for _, o := range allowedOrigins {
if origin == o {
w.Header().Set("Access-Control-Allow-Origin", origin)
w.Header().Set("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type,Authorization")
w.Header().Set("Access-Control-Allow-Credentials", "true")
}
}

// addCORSHeaders adds CORS header info for whitelisted servers
func (s *Server) addCORSHeaders(w http.ResponseWriter, r *http.Request) {
origin := r.Header.Get("Origin")
for _, o := range s.GetConfig().API.AllowedOrigins {
if origin == o {
w.Header().Set("Access-Control-Allow-Origin", origin)
w.Header().Set("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type,Authorization")
w.Header().Set("Access-Control-Allow-Credentials", "true")
return
}
// intercept OPTIONS requests with an early return
if r.Method == http.MethodOptions {
util.EmptyOkHandler(w, r)
return
}

next.ServeHTTP(w, r)
})
}
}

func (s *Server) readOnlyCheck(r *http.Request) bool {
return !s.GetConfig().API.ReadOnly || r.Method == "GET" || r.Method == "OPTIONS"
}

// muxVarsToQueryParamMiddleware moves all mux variables to query parameter
// values, failing with an error if a name collision with user-provided query
// params occurs
Expand Down

0 comments on commit 395d5ae

Please sign in to comment.