Skip to content

Commit 90cdcb7

Browse files
committedOct 16, 2017
Merge pull request #52933 from liggitt/proxy-subpath-slash
Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.. Preserve leading and trailing slashes on proxy subpaths subresource parsing was not populating path parameters correctly (leading and trailing slashes were being stripped) this caused bad locations to be sent to the proxy, causing kubernetes/kubernetes#52022. the first attempt to fix that (#52065) unconditionally prefixed '/', which broke the redirect case (#52813 #52729) fixes #52813, fixes #52729 needs to be picked to 1.7 and 1.8 ```release-note Restores redirect behavior for proxy subresources ``` Kubernetes-commit: e0f75338b5720fbce0aa02b0cf79965950089dbc
2 parents 92b434f + c6f7612 commit 90cdcb7

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed
 

‎pkg/util/net/http.go

+21
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,34 @@ import (
2626
"net/http"
2727
"net/url"
2828
"os"
29+
"path"
2930
"strconv"
3031
"strings"
3132

3233
"github.com/golang/glog"
3334
"golang.org/x/net/http2"
3435
)
3536

37+
// JoinPreservingTrailingSlash does a path.Join of the specified elements,
38+
// preserving any trailing slash on the last non-empty segment
39+
func JoinPreservingTrailingSlash(elem ...string) string {
40+
// do the basic path join
41+
result := path.Join(elem...)
42+
43+
// find the last non-empty segment
44+
for i := len(elem) - 1; i >= 0; i-- {
45+
if len(elem[i]) > 0 {
46+
// if the last segment ended in a slash, ensure our result does as well
47+
if strings.HasSuffix(elem[i], "/") && !strings.HasSuffix(result, "/") {
48+
result += "/"
49+
}
50+
break
51+
}
52+
}
53+
54+
return result
55+
}
56+
3657
// IsProbableEOF returns true if the given error resembles a connection termination
3758
// scenario that would justify assuming that the watch is empty.
3859
// These errors are what the Go http stack returns back to us which are general

‎pkg/util/net/http_test.go

+38
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package net
2020

2121
import (
2222
"crypto/tls"
23+
"fmt"
2324
"net"
2425
"net/http"
2526
"net/url"
@@ -218,3 +219,40 @@ func TestTLSClientConfigHolder(t *testing.T) {
218219
t.Errorf("didn't find tls config")
219220
}
220221
}
222+
223+
func TestJoinPreservingTrailingSlash(t *testing.T) {
224+
tests := []struct {
225+
a string
226+
b string
227+
want string
228+
}{
229+
// All empty
230+
{"", "", ""},
231+
232+
// Empty a
233+
{"", "/", "/"},
234+
{"", "foo", "foo"},
235+
{"", "/foo", "/foo"},
236+
{"", "/foo/", "/foo/"},
237+
238+
// Empty b
239+
{"/", "", "/"},
240+
{"foo", "", "foo"},
241+
{"/foo", "", "/foo"},
242+
{"/foo/", "", "/foo/"},
243+
244+
// Both populated
245+
{"/", "/", "/"},
246+
{"foo", "foo", "foo/foo"},
247+
{"/foo", "/foo", "/foo/foo"},
248+
{"/foo/", "/foo/", "/foo/foo/"},
249+
}
250+
for _, tt := range tests {
251+
name := fmt.Sprintf("%q+%q=%q", tt.a, tt.b, tt.want)
252+
t.Run(name, func(t *testing.T) {
253+
if got := JoinPreservingTrailingSlash(tt.a, tt.b); got != tt.want {
254+
t.Errorf("JoinPreservingTrailingSlash() = %v, want %v", got, tt.want)
255+
}
256+
})
257+
}
258+
}

0 commit comments

Comments
 (0)