mirror of
https://github.com/valyala/fasthttp.git
synced 2026-06-13 15:46:49 +03:00
Properly handle hashes and single dots in URI.Update (see https://github.com/kataras/iris/issues/173)
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
@@ -360,6 +361,20 @@ func b2s(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
// s2b converts string to a byte slice without memory allocation.
|
||||
//
|
||||
// Note it may break if string and/or slice header will change
|
||||
// in the future go versions.
|
||||
func s2b(s string) []byte {
|
||||
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
|
||||
bh := reflect.SliceHeader{
|
||||
Data: sh.Data,
|
||||
Len: sh.Len,
|
||||
Cap: sh.Len,
|
||||
}
|
||||
return *(*[]byte)(unsafe.Pointer(&bh))
|
||||
}
|
||||
|
||||
// AppendQuotedArg appends url-encoded src to dst and returns appended dst.
|
||||
func AppendQuotedArg(dst, src []byte) []byte {
|
||||
for _, c := range src {
|
||||
|
||||
@@ -286,8 +286,19 @@ func normalizePath(dst, src []byte) []byte {
|
||||
}
|
||||
dst = dst[:bSize]
|
||||
|
||||
// remove /foo/../ parts
|
||||
// remove /./ parts
|
||||
b = dst
|
||||
for {
|
||||
n := bytes.Index(b, strSlashDotSlash)
|
||||
if n < 0 {
|
||||
break
|
||||
}
|
||||
nn := n + len(strSlashDotSlash) - 1
|
||||
copy(b[n:], b[nn:])
|
||||
b = b[:len(b)-nn+n]
|
||||
}
|
||||
|
||||
// remove /foo/../ parts
|
||||
for {
|
||||
n := bytes.Index(b, strSlashDotDotSlash)
|
||||
if n < 0 {
|
||||
@@ -302,17 +313,6 @@ func normalizePath(dst, src []byte) []byte {
|
||||
b = b[:len(b)-n+nn]
|
||||
}
|
||||
|
||||
// remove /./ parts
|
||||
for {
|
||||
n := bytes.Index(b, strSlashDotSlash)
|
||||
if n < 0 {
|
||||
break
|
||||
}
|
||||
nn := n + len(strSlashDotSlash) - 1
|
||||
copy(b[n:], b[nn:])
|
||||
b = b[:len(b)-nn+n]
|
||||
}
|
||||
|
||||
// remove trailing /foo/..
|
||||
n := bytes.LastIndex(b, strSlashDotDot)
|
||||
if n >= 0 && n+len(strSlashDotDot) == len(b) {
|
||||
@@ -371,8 +371,7 @@ func (u *URI) LastPathSegment() []byte {
|
||||
// * Relative path, i.e. xx?yy=abc . In this case the original RequestURI
|
||||
// is updated according to the new relative path.
|
||||
func (u *URI) Update(newURI string) {
|
||||
u.fullURI = append(u.fullURI[:0], newURI...)
|
||||
u.UpdateBytes(u.fullURI)
|
||||
u.UpdateBytes(s2b(newURI))
|
||||
}
|
||||
|
||||
// UpdateBytes updates uri.
|
||||
@@ -409,22 +408,28 @@ func (u *URI) updateBytes(newURI, buf []byte) []byte {
|
||||
}
|
||||
|
||||
// relative path
|
||||
if newURI[0] == '?' {
|
||||
switch newURI[0] {
|
||||
case '?':
|
||||
// query string only update
|
||||
u.SetQueryStringBytes(newURI[1:])
|
||||
return append(buf[:0], u.FullURI()...)
|
||||
case '#':
|
||||
// update only hash
|
||||
u.SetHashBytes(newURI[1:])
|
||||
return append(buf[:0], u.FullURI()...)
|
||||
default:
|
||||
// update the last path part after the slash
|
||||
path := u.Path()
|
||||
n = bytes.LastIndexByte(path, '/')
|
||||
if n < 0 {
|
||||
panic("BUG: path must contain at least one slash")
|
||||
}
|
||||
buf = u.appendSchemeHost(buf[:0])
|
||||
buf = appendQuotedPath(buf, path[:n+1])
|
||||
buf = append(buf, newURI...)
|
||||
u.Parse(nil, buf)
|
||||
return buf
|
||||
}
|
||||
|
||||
path := u.Path()
|
||||
n = bytes.LastIndexByte(path, '/')
|
||||
if n < 0 {
|
||||
panic("BUG: path must contain at least one slash")
|
||||
}
|
||||
buf = u.appendSchemeHost(buf[:0])
|
||||
buf = appendQuotedPath(buf, path[:n+1])
|
||||
buf = append(buf, newURI...)
|
||||
u.Parse(nil, buf)
|
||||
return buf
|
||||
}
|
||||
|
||||
// FullURI returns full uri in the form {Scheme}://{Host}{RequestURI}#{Hash}.
|
||||
|
||||
@@ -109,6 +109,9 @@ func TestURIUpdate(t *testing.T) {
|
||||
testURIUpdate(t, "http://foo.bar/baz", "~a/%20b=c,тест?йцу=ке", "http://foo.bar/~a/%20b=c,%D1%82%D0%B5%D1%81%D1%82?йцу=ке")
|
||||
testURIUpdate(t, "http://foo.bar/baz", "/qwe#fragment", "http://foo.bar/qwe#fragment")
|
||||
testURIUpdate(t, "http://foobar/baz/xxx", "aaa.html#bb?cc=dd&ee=dfd", "http://foobar/baz/aaa.html#bb?cc=dd&ee=dfd")
|
||||
|
||||
// hash
|
||||
testURIUpdate(t, "http://foo.bar/baz#aaa", "#fragment", "http://foo.bar/baz#fragment")
|
||||
}
|
||||
|
||||
func testURIUpdate(t *testing.T, base, update, result string) {
|
||||
@@ -166,6 +169,7 @@ func TestURIPathNormalize(t *testing.T) {
|
||||
testURIPathNormalize(t, &u, "/a/./b/././c/./d.html", "/a/b/c/d.html")
|
||||
testURIPathNormalize(t, &u, "./foo/", "/foo/")
|
||||
testURIPathNormalize(t, &u, "./../.././../../aaa/bbb/../../../././../", "/")
|
||||
testURIPathNormalize(t, &u, "./a/./.././../b/./foo.html", "/b/foo.html")
|
||||
}
|
||||
|
||||
func testURIPathNormalize(t *testing.T, u *URI, requestURI, expectedPath string) {
|
||||
|
||||
Reference in New Issue
Block a user