Former-commit-id: 7de62d36b7927d790f5af0c1e64713e0a78d12c5
This commit is contained in:
Gerasimos Maropoulos 2018-03-13 15:57:52 +02:00
parent 05b1e80e7f
commit 5e5e91e4bb
2 changed files with 106 additions and 12 deletions

View File

@ -7,6 +7,7 @@ import (
"strings" "strings"
"github.com/kataras/iris/core/netutil" "github.com/kataras/iris/core/netutil"
"github.com/kataras/iris/core/router/macro/interpreter/lexer"
) )
const ( const (
@ -73,30 +74,91 @@ func joinPath(path1 string, path2 string) string {
// iteratively until no further processing can be done: // iteratively until no further processing can be done:
// //
// 1. Replace multiple slashes with a single slash. // 1. Replace multiple slashes with a single slash.
// 3. Eliminate each inner .. path name element (the parent directory) // 2. Replace '\' with '/'
// along with the non-.. element that precedes it. // 3. Replace "\\" with '/'
// 4. Eliminate .. elements that begin a rooted path: // 4. Ignore anything inside '{' and '}'
// that is, replace "/.." by "/" at the beginning of a path. // 5. Makes sure that prefixed with '/'
// 6. Remove trailing '/'.
// //
// The returned path ends in a slash only if it is the root "/". // The returned path ends in a slash only if it is the root "/".
func cleanPath(s string) string { func cleanPath(s string) string {
// note that we don't care about the performance here, it's before the server ran.
if s == "" || s == "." { if s == "" || s == "." {
return "/" return "/"
} }
// remove suffix "/" // remove suffix "/".
if lidx := len(s) - 1; s[lidx] == '/' { if lidx := len(s) - 1; s[lidx] == '/' {
s = s[:lidx] s = s[:lidx]
} }
// prefix with "/" // prefix with "/".
s = prefix(s, "/") s = prefix(s, "/")
// remove the os specific dir sep // If you're learning go through Iris I will ask you to ignore the
s = strings.Replace(s, "\\", "/", -1) // following part, it's not the recommending way to do that,
// but it's understable to me.
var (
insideMacro = false
i = -1
)
// use std path to clean the path for {
s = path.Clean(s) i++
if len(s) <= i {
break
}
if s[i] == lexer.Begin {
insideMacro = true
continue
}
if s[i] == lexer.End {
insideMacro = false
continue
}
// when inside {} then don't try to clean it.
if !insideMacro {
if s[i] == '/' {
if len(s)-1 >= i+1 && s[i+1] == '/' { // we have "//".
bckp := s
s = bckp[:i] + "/"
// forward two, we ignore the second "/" in the raw.
i = i + 2
if len(bckp)-1 >= i {
s += bckp[i:]
}
}
// if we have just a single slash then continue.
continue
}
if s[i] == '\\' { // this will catch "\\" and "\".
bckp := s
s = bckp[:i] + "/"
if len(bckp)-1 >= i+1 {
s += bckp[i+1:]
i++
}
if len(s)-1 > i && s[i] == '\\' {
bckp := s
s = bckp[:i]
if len(bckp)-1 >= i+2 {
s = bckp[:i-1] + bckp[i+1:]
i++
}
}
continue
}
}
}
return s return s
} }

View File

@ -4,6 +4,38 @@ import (
"testing" "testing"
) )
func TestCleanPath(t *testing.T) {
tests := []struct {
path string
expected string
}{
{"noslashPrefix",
"/noslashPrefix"},
{"slashSuffix/",
"/slashSuffix"},
{"noSlashPrefixAndslashSuffix/",
"/noSlashPrefixAndslashSuffix"},
// don't do any clean up inside {},
// fixes #927.
{"/total/{year:string regexp(\\d{4})}",
"/total/{year:string regexp(\\d{4})}"},
{"/total/{year:string regexp(\\d{4})}/more",
"/total/{year:string regexp(\\d{4})}/more"},
{"/total/{year:string regexp(\\d{4})}/more/{s:string regexp(\\d{7})}",
"/total/{year:string regexp(\\d{4})}/more/{s:string regexp(\\d{7})}"},
{"/single_no_params",
"/single_no_params"},
{"/single/{id:int}",
"/single/{id:int}"},
}
for i, tt := range tests {
if expected, got := tt.expected, cleanPath(tt.path); expected != got {
t.Fatalf("[%d] - expected path '%s' but got '%s'", i, expected, got)
}
}
}
func TestSplitPath(t *testing.T) { func TestSplitPath(t *testing.T) {
tests := []struct { tests := []struct {
path string path string
@ -50,8 +82,8 @@ func TestSplitSubdomainAndPath(t *testing.T) {
}{ }{
{"admin./users/42", "admin.", "/users/42"}, {"admin./users/42", "admin.", "/users/42"},
{"//api/users\\42", "", "/api/users/42"}, {"//api/users\\42", "", "/api/users/42"},
{"admin./users/\\42", "admin.", "/users/42"}, {"admin./users//42", "admin.", "/users/42"},
{"*./users/\\42", "*.", "/users/42"}, {"*./users/42/", "*.", "/users/42"},
} }
for i, tt := range tests { for i, tt := range tests {