github.com/splucs/witchcraft-go-server@v1.7.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/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) PathParams(req *http.Request, pathVarNames []string) map[string]string { 79 _, vars, _ := (*httprouter.Router)(r).Lookup(req.Method, req.URL.Path) 80 if len(vars) == 0 { 81 return nil 82 } 83 params := make(map[string]string) 84 for i := range vars { 85 // strip preceding forward slashes for trailing match path params. httprouter is implemented such that, 86 // for a trailing parameter for the form "/{param*}", the path "/var/foo/bar.txt" will match with a 87 // value of "/var/foo/bar.txt". However, the contract of zappermux stipulates that the match should be 88 // of the form "var/foo/bar.txt", so strip the preceding slash to fulfill this contract. 89 params[vars[i].Key] = strings.TrimPrefix(vars[i].Value, "/") 90 } 91 return params 92 } 93 94 func (r *router) convertPathParams(pathSegments []wrouter.PathSegment) string { 95 pathParts := make([]string, len(pathSegments)) 96 for i, segment := range pathSegments { 97 switch segment.Type { 98 case wrouter.PathParamSegment: 99 pathParts[i] = ":" + segment.Value 100 case wrouter.TrailingPathParamSegment: 101 pathParts[i] = "*" + segment.Value 102 default: 103 pathParts[i] = segment.Value 104 } 105 } 106 return "/" + strings.Join(pathParts, "/") 107 }