From a6f6032286b16ac7cbca516564547fa7adccf070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E4=BA=91=E5=B9=B3?= Date: Mon, 22 Jul 2019 16:51:19 +0800 Subject: [PATCH 1/3] add current route --- dispatcher.go | 15 ++++++++++++--- go.mod | 5 +++++ go.sum | 13 +++++++++++++ tree.go | 9 ++++++++- tree_test.go | 8 ++++---- 5 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 go.mod create mode 100644 go.sum diff --git a/dispatcher.go b/dispatcher.go index 274c779..f645647 100644 --- a/dispatcher.go +++ b/dispatcher.go @@ -80,9 +80,16 @@ package httpdispatch import ( + "context" "net/http" ) +type ContextKey int + +const ( + ContextKeyRoute ContextKey = iota +) + // Handler is an interface that can be registered to a route to handle HTTP // requests. Like http.HandlerFunc, but has a third parameter for the values of // wildcards (variables). @@ -235,7 +242,8 @@ func (d *Dispatcher) ServeFiles(path string, fs http.FileSystem) { // the same path with / without the trailing slash should be performed. func (d *Dispatcher) Lookup(method, path string) (Handler, Params, bool) { if root := d.trees[method]; root != nil { - return root.getValue(path) + handler, params, tsr, _ := root.getValue(path) + return handler, params, tsr } return nil, nil, false @@ -250,10 +258,11 @@ func (d *Dispatcher) ServeHTTP(w http.ResponseWriter, r *http.Request) { path := r.URL.Path if root := d.trees[r.Method]; root != nil { - handler, params, tsr := root.getValue(path) + handler, params, tsr, route := root.getValue(path) if handler != nil { if !tsr || !d.RedirectTrailingSlash { + r = r.WithContext(context.WithValue(r.Context(), ContextKeyRoute, route)) handler.Handle(w, r, params) return } @@ -382,7 +391,7 @@ func (d *Dispatcher) allowed(path, reqMethod string) (allow string) { continue } - handler, _, _ := d.trees[method].getValue(path) + handler, _, _, _ := d.trees[method].getValue(path) if handler != nil { // add request method to list of allowed methods if len(allow) == 0 { diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..6c50abd --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/dolab/httpdispatch + +go 1.12 + +require github.com/golib/assert v1.3.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..add8087 --- /dev/null +++ b/go.sum @@ -0,0 +1,13 @@ +github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 h1:D21IyuvjDCshj1/qq+pCNd3VZOAEI9jy6Bi131YlXgI= +github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/dolab/types v0.0.0-20181115071224-9f9f8147c117 h1:w7dIqNfQuaVBTSMCHx0q32k4gM3vN5ZRJKs73EhEnIA= +github.com/dolab/types v0.0.0-20181115071224-9f9f8147c117/go.mod h1:ye5M9z0YlIxn/I+vU4MlK18SuRdSl62pxjMI6CdlFGg= +github.com/golib/assert v1.3.0 h1:0zlb71NpB0q5FHMnYHyTnh+IS1+6YwW26ARpgN/0PA4= +github.com/golib/assert v1.3.0/go.mod h1:hyMJSCLv/DFMNpTYmEaAd+OYj1KqmB5pZ7WlKGj7sGo= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= diff --git a/tree.go b/tree.go index 0e237cb..d66fbe4 100644 --- a/tree.go +++ b/tree.go @@ -321,7 +321,8 @@ func (n *node) insertChild(numParams uint8, path, fullPath string, handle Handle // made if a handle exists with an extra (without the) trailing slash for the // given path. // It returns handle also if a TSR is true. Its useful for quick fallback strategy. -func (n *node) getValue(path string) (handle Handler, p Params, tsr bool) { +func (n *node) getValue(path string) (handle Handler, p Params, tsr bool, route string) { + route = "/" walk: // outer loop for walking the tree for { switch { @@ -345,6 +346,7 @@ walk: // outer loop for walking the tree for i := 0; i < len(n.indices); i++ { if c == n.indices[i] { n = n.children[i] + route += "/" + n.path continue walk } } @@ -354,6 +356,8 @@ walk: // outer loop for walking the tree // handle wildcard child n = n.children[0] + route += "/" + n.path + switch n.typo { case param: // save param value @@ -387,6 +391,7 @@ walk: // outer loop for walking the tree if len(n.children) > 0 { path = path[end:] n = n.children[0] + route += "/" + n.path continue walk } @@ -404,6 +409,7 @@ walk: // outer loop for walking the tree // trailing slash exists for TSR recommendation if len(n.children) == 1 { n = n.children[0] + route += "/" + n.path tsr = (n.path == "/" && n.handle != nil) if tsr { @@ -457,6 +463,7 @@ walk: // outer loop for walking the tree for i := 0; i < len(n.indices); i++ { if n.indices[i] == '/' { n = n.children[i] + route += "/" + n.path tsr = (len(n.path) == 1 && n.handle != nil) if tsr { diff --git a/tree_test.go b/tree_test.go index 7dfd313..a2dcc78 100644 --- a/tree_test.go +++ b/tree_test.go @@ -42,7 +42,7 @@ type testRequests []struct { func checkRequests(t *testing.T, tree *node, requests testRequests) { for _, request := range requests { - handler, ps, tsr := tree.getValue(request.path) + handler, ps, tsr, _ := tree.getValue(request.path) if tsr { if handler != nil { @@ -470,7 +470,7 @@ func TestTreeTrailingSlashRedirect(t *testing.T) { "/doc/", } for _, route := range tsrRoutes { - handler, _, tsr := tree.getValue(route) + handler, _, tsr, _ := tree.getValue(route) if handler != nil && !tsr { t.Fatalf("non-nil handler for TSR route '%s", route) } else if !tsr { @@ -487,7 +487,7 @@ func TestTreeTrailingSlashRedirect(t *testing.T) { "/api/world/abc", } for _, route := range noTsrRoutes { - handler, _, tsr := tree.getValue(route) + handler, _, tsr, _ := tree.getValue(route) if handler != nil { t.Fatalf("non-nil handler for No-TSR route '%s", route) } else if tsr { @@ -506,7 +506,7 @@ func TestTreeRootTrailingSlashRedirect(t *testing.T) { t.Fatalf("panic inserting test route: %v", recv) } - handler, _, tsr := tree.getValue("/") + handler, _, tsr, _ := tree.getValue("/") if handler != nil { t.Fatalf("non-nil handler") } else if tsr { From 3cffbea8254e62f823285e9ba01955ef2d20084c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E4=BA=91=E5=B9=B3?= Date: Mon, 22 Jul 2019 17:05:04 +0800 Subject: [PATCH 2/3] fix double slash --- tree.go | 1 - 1 file changed, 1 deletion(-) diff --git a/tree.go b/tree.go index d66fbe4..26f8366 100644 --- a/tree.go +++ b/tree.go @@ -322,7 +322,6 @@ func (n *node) insertChild(numParams uint8, path, fullPath string, handle Handle // given path. // It returns handle also if a TSR is true. Its useful for quick fallback strategy. func (n *node) getValue(path string) (handle Handler, p Params, tsr bool, route string) { - route = "/" walk: // outer loop for walking the tree for { switch { From 5ac8d35491de3c57c57552c34f9e99d5e022a3d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E4=BA=91=E5=B9=B3?= Date: Mon, 22 Jul 2019 17:06:35 +0800 Subject: [PATCH 3/3] fix double slash --- tree.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tree.go b/tree.go index 26f8366..a98a03b 100644 --- a/tree.go +++ b/tree.go @@ -322,6 +322,7 @@ func (n *node) insertChild(numParams uint8, path, fullPath string, handle Handle // given path. // It returns handle also if a TSR is true. Its useful for quick fallback strategy. func (n *node) getValue(path string) (handle Handler, p Params, tsr bool, route string) { + route = "/" walk: // outer loop for walking the tree for { switch { @@ -345,7 +346,7 @@ walk: // outer loop for walking the tree for i := 0; i < len(n.indices); i++ { if c == n.indices[i] { n = n.children[i] - route += "/" + n.path + route += n.path continue walk } } @@ -355,7 +356,7 @@ walk: // outer loop for walking the tree // handle wildcard child n = n.children[0] - route += "/" + n.path + route += n.path switch n.typo { case param: @@ -390,7 +391,7 @@ walk: // outer loop for walking the tree if len(n.children) > 0 { path = path[end:] n = n.children[0] - route += "/" + n.path + route += n.path continue walk } @@ -408,7 +409,7 @@ walk: // outer loop for walking the tree // trailing slash exists for TSR recommendation if len(n.children) == 1 { n = n.children[0] - route += "/" + n.path + route += n.path tsr = (n.path == "/" && n.handle != nil) if tsr { @@ -462,7 +463,7 @@ walk: // outer loop for walking the tree for i := 0; i < len(n.indices); i++ { if n.indices[i] == '/' { n = n.children[i] - route += "/" + n.path + route += n.path tsr = (len(n.path) == 1 && n.handle != nil) if tsr {