github.com/mendersoftware/go-lib-micro@v0.0.0-20240304135804-e8e39c59b148/routing/routing.go (about)

     1  // Copyright 2023 Northern.tech AS
     2  //
     3  //	Licensed under the Apache License, Version 2.0 (the "License");
     4  //	you may not use this file except in compliance with the License.
     5  //	You may obtain a copy of the License at
     6  //
     7  //	    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  //	Unless required by applicable law or agreed to in writing, software
    10  //	distributed under the License is distributed on an "AS IS" BASIS,
    11  //	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  //	See the License for the specific language governing permissions and
    13  //	limitations under the License.
    14  package routing
    15  
    16  import (
    17  	"net/http"
    18  
    19  	"github.com/ant0ine/go-json-rest/rest"
    20  
    21  	"github.com/mendersoftware/go-lib-micro/strings"
    22  )
    23  
    24  type HttpOptionsGenerator func(methods []string) rest.HandlerFunc
    25  
    26  func AllowHeaderOptionsGenerator(methods []string) rest.HandlerFunc {
    27  	// return a dummy handler for now
    28  	return func(w rest.ResponseWriter, r *rest.Request) {
    29  		for _, m := range methods {
    30  			w.Header().Add("Allow", m)
    31  		}
    32  	}
    33  }
    34  
    35  func supportsMethod(method string, methods []string) bool {
    36  	return strings.ContainsString(method, methods)
    37  }
    38  
    39  // Automatically add OPTIONS method support for each defined route,
    40  // only if there's no OPTIONS handler for that route yet
    41  func AutogenOptionsRoutes(routes []*rest.Route, gen HttpOptionsGenerator) []*rest.Route {
    42  
    43  	methodGroups := make(map[string][]string, len(routes))
    44  
    45  	for _, route := range routes {
    46  		methods, ok := methodGroups[route.PathExp]
    47  		if !ok {
    48  			methods = make([]string, 0, 0)
    49  		}
    50  
    51  		methodGroups[route.PathExp] = append(methods, route.HttpMethod)
    52  	}
    53  
    54  	options := make([]*rest.Route, 0, len(methodGroups))
    55  	for route, methods := range methodGroups {
    56  		// skip if there's a handler for OPTIONS already
    57  		if supportsMethod(http.MethodOptions, methods) == false {
    58  			options = append(options,
    59  				rest.Options(route, gen(methods)))
    60  		}
    61  	}
    62  
    63  	return append(routes, options...)
    64  }