github.com/palantir/witchcraft-go-server/v2@v2.76.0/wrouter/whttprouter/routerimpl.go (about) 1 // Copyright (c) 2018 Palantir Technologies. All rights reserved. 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 15 package whttprouter 16 17 import ( 18 "net/http" 19 "strings" 20 21 "github.com/julienschmidt/httprouter" 22 "github.com/palantir/witchcraft-go-server/v2/wrouter" 23 ) 24 25 // New returns a wrouter.RouterImpl backed by a new httprouter.Router configured using the provided parameters. 26 func New(params ...Param) wrouter.RouterImpl { 27 r := httprouter.New() 28 for _, p := range params { 29 p.apply(r) 30 } 31 return (*router)(r) 32 } 33 34 type Param interface { 35 apply(*httprouter.Router) 36 } 37 38 type paramFunc func(*httprouter.Router) 39 40 func (f paramFunc) apply(r *httprouter.Router) { 41 f(r) 42 } 43 44 func RedirectTrailingSlash(redirect bool) Param { 45 return paramFunc(func(r *httprouter.Router) { 46 r.RedirectTrailingSlash = redirect 47 }) 48 } 49 50 func RedirectFixedPath(redirect bool) Param { 51 return paramFunc(func(r *httprouter.Router) { 52 r.RedirectFixedPath = redirect 53 }) 54 } 55 56 func HandleMethodNotAllowed(notAllowed bool) Param { 57 return paramFunc(func(r *httprouter.Router) { 58 r.HandleMethodNotAllowed = notAllowed 59 }) 60 } 61 62 func HandleOPTIONS(handle bool) Param { 63 return paramFunc(func(r *httprouter.Router) { 64 r.HandleOPTIONS = handle 65 }) 66 } 67 68 type router httprouter.Router 69 70 func (r *router) ServeHTTP(w http.ResponseWriter, req *http.Request) { 71 (*httprouter.Router)(r).ServeHTTP(w, req) 72 } 73 74 func (r *router) Register(method string, pathSegments []wrouter.PathSegment, handler http.Handler) { 75 (*httprouter.Router)(r).Handler(method, r.convertPathParams(pathSegments), handler) 76 } 77 78 func (r *router) RegisterNotFoundHandler(handler http.Handler) { 79 (*httprouter.Router)(r).NotFound = handler 80 } 81 82 func (r *router) PathParams(req *http.Request, pathVarNames []string) map[string]string { 83 _, vars, _ := (*httprouter.Router)(r).Lookup(req.Method, req.URL.Path) 84 if len(vars) == 0 { 85 return nil 86 } 87 params := make(map[string]string) 88 for i := range vars { 89 // strip preceding forward slashes for trailing match path params. httprouter is implemented such that, 90 // for a trailing parameter for the form "/{param*}", the path "/var/foo/bar.txt" will match with a 91 // value of "/var/foo/bar.txt". However, the contract of zappermux stipulates that the match should be 92 // of the form "var/foo/bar.txt", so strip the preceding slash to fulfill this contract. 93 params[vars[i].Key] = strings.TrimPrefix(vars[i].Value, "/") 94 } 95 return params 96 } 97 98 func (r *router) convertPathParams(pathSegments []wrouter.PathSegment) string { 99 pathParts := make([]string, len(pathSegments)) 100 for i, segment := range pathSegments { 101 switch segment.Type { 102 case wrouter.PathParamSegment: 103 pathParts[i] = ":" + segment.Value 104 case wrouter.TrailingPathParamSegment: 105 pathParts[i] = "*" + segment.Value 106 default: 107 pathParts[i] = segment.Value 108 } 109 } 110 return "/" + strings.Join(pathParts, "/") 111 }