Fix .Path(...)/.Url(...) and {{url ...}}/{{ urlpath ...} on httprouter Adaptor. https://github.com/kataras/iris/issues/606

Former-commit-id: f5cb496ee151a7a85361f6ed5eeb2a8231eb2fff
This commit is contained in:
Gerasimos (Makis) Maropoulos 2017-02-18 08:03:14 +02:00
parent f83c7fb4e7
commit e4079e4c67
4 changed files with 103 additions and 50 deletions

View File

@ -0,0 +1,22 @@
package gorillamux_test
import (
"testing"
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/gorillamux"
)
func TestRouteURLPath(t *testing.T) {
app := iris.New()
app.Adapt(gorillamux.New())
app.None("/profile/{user_id}/{ref}/{anything:.*}", nil).ChangeName("profile")
app.Boot()
expected := "/profile/42/iris-go/something"
if got := app.Path("profile", "user_id", 42, "ref", "iris-go", "anything", "something"); got != expected {
t.Fatalf("httprouter's reverse routing 'URLPath' error: expected %s but got %s", expected, got)
}
}

View File

@ -25,6 +25,7 @@ package httprouter
// }
import (
"fmt"
"net/http"
"strings"
@ -461,6 +462,40 @@ type (
}
)
// path = "/api/users/:id"
// return "/api/users/%v"
//
// path = "/files/*file"
// return /files/%v
//
// path = "/:username/messages/:messageid"
// return "/%v/messages/%v"
func formatPath(path string) string {
n1Len := strings.Count(path, ":")
isMatchEverything := len(path) > 0 && path[len(path)-1] == matchEverythingByte
if n1Len == 0 && !isMatchEverything {
// its a static
return path
}
if n1Len == 0 && isMatchEverything {
//if we have something like: /mypath/anything/* -> /mypatch/anything/%v
return path[0:len(path)-2] + "%v"
}
splittedN1 := strings.Split(path, "/")
for _, v := range splittedN1 {
if len(v) > 0 {
if v[0] == ':' || v[0] == matchEverythingByte {
path = strings.Replace(path, v, "%v", -1) // n1Len, but let it we don't care about performance here.
}
}
}
return path
}
// New returns a new iris' policy to create and attach the router.
// It's based on the julienschmidt/httprouter with more features and some iris-relative performance tips:
// subdomains(wildcard/dynamic and static) and faster parameters set (use of the already-created context's values)
@ -497,55 +532,37 @@ func New() iris.Policies {
WildcardPath: func(path string, paramName string) string {
return path + slash + matchEverythingString + paramName
},
// path = "/api/users/:id", args = ["42"]
// return "/api/users/42"
//
// path = "/files/*file", args = ["mydir","myfile.zip"]
// return /files/mydir/myfile.zip
//
// path = "/:username/messages/:messageid", args = ["kataras","42"]
// return "/kataras/messages/42"
//
// This policy is used for reverse routing,
// see iris.Path/URL and ~/adaptors/view/ {{ url }} {{ urlpath }}
URLPath: func(r iris.RouteInfo, args ...string) string {
rpath := r.Path()
formattedPath := formatPath(rpath)
// URLPath: func(r iris.RouteInfo, args ...string) string {
// argsLen := len(args)
//
// // we have named parameters but arguments not given
// if argsLen == 0 && r.formattedParts > 0 {
// return ""
// } else if argsLen == 0 && r.formattedParts == 0 {
// // it's static then just return the path
// return r.path
// }
//
// // we have arguments but they are much more than the named parameters
//
// // 1 check if we have /*, if yes then join all arguments to one as path and pass that as parameter
// if argsLen > r.formattedParts {
// if r.path[len(r.path)-1] == matchEverythingByte {
// // we have to convert each argument to a string in this case
//
// argsString := make([]string, argsLen, argsLen)
//
// for i, v := range args {
// if s, ok := v.(string); ok {
// argsString[i] = s
// } else if num, ok := v.(int); ok {
// argsString[i] = strconv.Itoa(num)
// } else if b, ok := v.(bool); ok {
// argsString[i] = strconv.FormatBool(b)
// } else if arr, ok := v.([]string); ok {
// if len(arr) > 0 {
// argsString[i] = arr[0]
// argsString = append(argsString, arr[1:]...)
// }
// }
// }
//
// parameter := strings.Join(argsString, slash)
// result := fmt.Sprintf(r.formattedPath, parameter)
// return result
// }
// // 2 if !1 return false
// return ""
// }
//
// arguments := joinPathArguments(args...)
//
// return fmt.Sprintf(r.formattedPath, arguments...)
// },
if rpath == formattedPath {
// static, no need to pass args
return rpath
}
// check if we have /*, if yes then join all arguments to one as path and pass that as parameter
if formattedPath != rpath && rpath[len(rpath)-1] == matchEverythingByte {
parameter := strings.Join(args, slash)
return fmt.Sprintf(formattedPath, parameter)
}
// else return the formattedPath with its args
for _, s := range args {
formattedPath = strings.Replace(formattedPath, "%v", s, 1)
}
return formattedPath
},
},
RouterBuilderPolicy: func(repo iris.RouteRepository, context iris.ContextPool) http.Handler {
fatalErr := false

View File

@ -284,3 +284,17 @@ func TestMuxCustomErrors(t *testing.T) {
Status(r.Status).Body().Equal(r.Body)
}
}
func TestRouteURLPath(t *testing.T) {
app := iris.New()
app.Adapt(httprouter.New())
app.None("/profile/:user_id/:ref/*anything", nil).ChangeName("profile")
app.Boot()
expected := "/profile/42/iris-go/something"
if got := app.Path("profile", 42, "iris-go", "something"); got != expected {
t.Fatalf("httprouter's reverse routing 'URLPath' error: expected %s but got %s", expected, got)
}
}

View File

@ -121,7 +121,7 @@ type testNativeRoute struct {
status int
}
func TestRouterPolicyAdaptor(t *testing.T) {
func TestNativeRouterPolicyAdaptor(t *testing.T) {
expectedWrongMethodStatus := StatusNotFound
app := New(Configuration{FireMethodNotAllowed: true})
app.Adapt(newTestNativeRouter())
@ -166,9 +166,9 @@ func TestRouterPolicyAdaptor(t *testing.T) {
}).ChangeName("profile")
e := httptest.New(app, t)
expected := "/profile/?user_id=42&ref=iris-go&something=anything"
expected := "/profile/?user_id=42&ref=iris-go&anything=something"
if got := app.Path("profile", "user_id", 42, "ref", "iris-go", "something", "anything"); got != expected {
if got := app.Path("profile", "user_id", 42, "ref", "iris-go", "anything", "something"); got != expected {
t.Fatalf("URLPath expected %s but got %s", expected, got)
}