Skip to content

Commit a322891

Browse files
Merge pull request #52947 from liggitt/automated-cherry-pick-of-#52933-upstream-release-1.7
Automatic merge from submit-queue. Automated cherry pick of #52933 Cherry pick of #52933 on release-1.7. #52933: Preserve leading and trailing slashes on proxy subpaths Kubernetes-commit: 7db3566ec9307c5a4de68028fdab05766608d2b1
2 parents 7c52ae4 + c61287a commit a322891

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

pkg/util/net/http.go

Lines changed: 21 additions & 0 deletions
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

Lines changed: 38 additions & 0 deletions
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)