fix: prevent incorrect binding
This commit is contained in:
@@ -60,7 +60,7 @@ func findChannelIncrement(route string) (incrementalRoute, bool) {
|
|||||||
}
|
}
|
||||||
pos += index
|
pos += index
|
||||||
|
|
||||||
start, end, ok := firstNumberAfter(route, pos+len(pattern))
|
start, end, ok := firstNumberAfterKey(route, pos+len(pattern))
|
||||||
if ok {
|
if ok {
|
||||||
num, width, parseOK := parseNumber(route, start, end)
|
num, width, parseOK := parseNumber(route, start, end)
|
||||||
if parseOK {
|
if parseOK {
|
||||||
@@ -131,23 +131,41 @@ func parseNumber(route string, start, end int) (int, int, bool) {
|
|||||||
return num, len(value), true
|
return num, len(value), true
|
||||||
}
|
}
|
||||||
|
|
||||||
// firstNumberAfter returns the first numeric token after a given index.
|
// firstNumberAfterKey returns the first numeric token after a keyword, limited to
|
||||||
func firstNumberAfter(route string, after int) (start, end int, ok bool) {
|
// the current token and requiring an '=' delimiter (query param or path segment).
|
||||||
|
func firstNumberAfterKey(route string, after int) (start, end int, ok bool) {
|
||||||
if after < 0 {
|
if after < 0 {
|
||||||
after = 0
|
after = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tokenEnd := len(route)
|
||||||
for i := after; i < len(route); i++ {
|
for i := after; i < len(route); i++ {
|
||||||
|
if isTokenDelimiter(route[i]) {
|
||||||
|
tokenEnd = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
relEq := strings.IndexByte(route[after:tokenEnd], '=')
|
||||||
|
searchStart := after
|
||||||
|
if relEq != -1 {
|
||||||
|
searchStart = after + relEq + 1
|
||||||
|
}
|
||||||
|
for i := searchStart; i < tokenEnd; i++ {
|
||||||
if !isDigit(route[i]) {
|
if !isDigit(route[i]) {
|
||||||
|
if relEq == -1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
end := i + 1
|
end := i + 1
|
||||||
for end < len(route) && isDigit(route[end]) {
|
for end < tokenEnd && isDigit(route[end]) {
|
||||||
end++
|
end++
|
||||||
}
|
}
|
||||||
return i, end, true
|
return i, end, true
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0, 0, false
|
return 0, 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,3 +181,12 @@ func buildIncrementedRoute(match incrementalRoute, number int) string {
|
|||||||
func isDigit(b byte) bool {
|
func isDigit(b byte) bool {
|
||||||
return b >= '0' && b <= '9'
|
return b >= '0' && b <= '9'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isTokenDelimiter(b byte) bool {
|
||||||
|
switch b {
|
||||||
|
case '&', '/', '?', '#':
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -66,6 +66,18 @@ func TestDetectIncrementalRoute_OverflowAtEndFallsBack(t *testing.T) {
|
|||||||
assert.Equal(t, "/bar999999999999999999999999999999", match.suffix)
|
assert.Equal(t, "/bar999999999999999999999999999999", match.suffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDetectIncrementalRoute_ChannelKeywordShouldNotBindAcrossParams(t *testing.T) {
|
||||||
|
// The channel keyword should not bind to digits in other query parameters.
|
||||||
|
route := "/path?channelname=foo&version=12"
|
||||||
|
|
||||||
|
match, ok := detectIncrementalRoute(route)
|
||||||
|
require.True(t, ok)
|
||||||
|
assert.False(t, match.isChannel)
|
||||||
|
assert.Equal(t, 12, match.number)
|
||||||
|
assert.Equal(t, "/path?channelname=foo&version=", match.prefix)
|
||||||
|
assert.Equal(t, "", match.suffix)
|
||||||
|
}
|
||||||
|
|
||||||
func TestBuildIncrementedRoute_ZeroPadding(t *testing.T) {
|
func TestBuildIncrementedRoute_ZeroPadding(t *testing.T) {
|
||||||
match := incrementalRoute{
|
match := incrementalRoute{
|
||||||
prefix: "/channel",
|
prefix: "/channel",
|
||||||
|
|||||||
Reference in New Issue
Block a user