Skip to content

Commit 43eb7fc

Browse files
committed
fix(serverHandler): ignore case for binded FileInfo
- gather name comparing logic into one place - archive matching should ignore case for binded FileInfo - bind-shadowed uploading checking should ignore case - bind-shadowed deleting should ignore case
1 parent 3861e74 commit 43eb7fc

32 files changed

+300
-54
lines changed

src/serverHandler/aliasAccurate.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func (alias aliasAccurate) caseSensitive() bool {
2626
}
2727

2828
func (alias aliasAccurate) isMatch(rawReqPath string) bool {
29-
return alias.url == rawReqPath
29+
return isNameEqualAccurate(alias.url, rawReqPath)
3030
}
3131

3232
func (alias aliasAccurate) isSuccessorOf(rawReqPath string) bool {
@@ -38,5 +38,5 @@ func (alias aliasAccurate) isPredecessorOf(rawReqPath string) bool {
3838
}
3939

4040
func (alias aliasAccurate) namesEqual(a, b string) bool {
41-
return a == b
41+
return isNameEqualAccurate(a, b)
4242
}

src/serverHandler/aliasNoCase.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package serverHandler
22

33
import (
44
"../util"
5-
"strings"
65
)
76

87
type aliasNoCase struct {
@@ -27,7 +26,7 @@ func (alias aliasNoCase) caseSensitive() bool {
2726
}
2827

2928
func (alias aliasNoCase) isMatch(rawReqPath string) bool {
30-
return strings.EqualFold(alias.url, rawReqPath)
29+
return isNameEqualNoCase(alias.url, rawReqPath)
3130
}
3231

3332
func (alias aliasNoCase) isSuccessorOf(rawReqPath string) bool {
@@ -39,5 +38,5 @@ func (alias aliasNoCase) isPredecessorOf(rawReqPath string) bool {
3938
}
4039

4140
func (alias aliasNoCase) namesEqual(a, b string) bool {
42-
return strings.EqualFold(a, b)
41+
return isNameEqualNoCase(a, b)
4342
}

src/serverHandler/archive.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,27 @@ import (
1111

1212
type archiveCallback func(f *os.File, fInfo os.FileInfo, relPath string) error
1313

14-
func matchSelection(name string, selections []string) (matchName, matchPrefix bool, childSelections []string) {
14+
func matchSelection(info os.FileInfo, selections []string) (matchName, matchPrefix bool, childSelections []string) {
1515
if len(selections) == 0 {
1616
return true, false, nil
1717
}
1818

19-
for _, sel := range selections {
20-
if sel == name {
19+
name := info.Name()
20+
isNameEqual := getIsNameEqualFunc(info)
21+
for _, selName := range selections {
22+
if isNameEqual(selName, name) {
2123
matchName = true
2224
continue
2325
}
2426

25-
slashIndex := strings.IndexByte(sel, '/')
27+
slashIndex := strings.IndexByte(selName, '/')
2628
if slashIndex <= 0 {
2729
continue
2830
}
2931

30-
prefix := sel[:slashIndex]
31-
if prefix == name {
32-
childSel := sel[slashIndex+1:]
32+
selNamePart1 := selName[:slashIndex]
33+
if isNameEqual(selNamePart1, name) {
34+
childSel := selName[slashIndex+1:]
3335
if len(childSel) > 0 {
3436
matchPrefix = true
3537
childSelections = append(childSelections, childSel)
@@ -99,13 +101,12 @@ func (h *handler) visitTreeNode(
99101

100102
// childInfo can be regular dir/file, or aliased item that shadows regular dir/file
101103
for _, childInfo := range childInfos {
102-
childName := childInfo.Name()
103-
matchChildName, matchChildPrefix, childChildSelections := matchSelection(childName, childSelections)
104+
matchChildName, matchChildPrefix, childChildSelections := matchSelection(childInfo, childSelections)
104105
if !matchChildName && !matchChildPrefix {
105106
continue
106107
}
107108

108-
childPath := "/" + childName
109+
childPath := "/" + childInfo.Name()
109110
childFsPath := fsPath + childPath
110111
childRawReqPath := util.CleanUrlPath(rawReqPath + childPath)
111112
childRelPath := relPath + childPath
@@ -169,7 +170,7 @@ func writeArchiveHeader(w http.ResponseWriter, contentType, filename string) {
169170
w.WriteHeader(http.StatusOK)
170171
}
171172

172-
func (h *handler) getArchiveSelections(r *http.Request) ([]string, bool) {
173+
func (h *handler) normalizeArchiveSelections(r *http.Request) ([]string, bool) {
173174
if h.errHandler.LogError(r.ParseForm()) {
174175
return nil, false
175176
}

src/serverHandler/archiveTar.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func (h *handler) tar(w http.ResponseWriter, r *http.Request, pageData *response
5353
return
5454
}
5555

56-
selections, ok := h.getArchiveSelections(r)
56+
selections, ok := h.normalizeArchiveSelections(r)
5757
if !ok {
5858
return
5959
}
@@ -83,7 +83,7 @@ func (h *handler) tgz(w http.ResponseWriter, r *http.Request, pageData *response
8383
return
8484
}
8585

86-
selections, ok := h.getArchiveSelections(r)
86+
selections, ok := h.normalizeArchiveSelections(r)
8787
if !ok {
8888
return
8989
}

src/serverHandler/archiveZip.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func (h *handler) zip(w http.ResponseWriter, r *http.Request, pageData *response
4343
return
4444
}
4545

46-
selections, ok := h.getArchiveSelections(r)
46+
selections, ok := h.normalizeArchiveSelections(r)
4747
if !ok {
4848
return
4949
}

src/serverHandler/archive_test.go

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package serverHandler
22

3-
import "testing"
3+
import (
4+
"os"
5+
"testing"
6+
)
47

58
func TestGetMatchInfo(t *testing.T) {
69
var matchName, matchPrefix bool
710
var childList []string
11+
var info os.FileInfo
812

913
var expect = func(isMatchName, isMatchPrefix bool, isChildList ...string) bool {
1014
if isMatchName != matchName {
@@ -18,6 +22,10 @@ func TestGetMatchInfo(t *testing.T) {
1822
return false
1923
}
2024

25+
if len(isChildList) != len(childList) {
26+
return false
27+
}
28+
2129
if isChildList != nil && childList != nil {
2230
for i := 0; i < len(isChildList); i++ {
2331
if isChildList[i] != childList[i] {
@@ -29,48 +37,63 @@ func TestGetMatchInfo(t *testing.T) {
2937
return true
3038
}
3139

32-
matchName, matchPrefix, childList = matchSelection("", nil)
40+
info = createPlaceholderFileInfo("", true)
41+
matchName, matchPrefix, childList = matchSelection(info, nil)
3342
if !expect(true, false) {
3443
t.Error(matchName, matchPrefix, childList)
3544
}
3645

37-
matchName, matchPrefix, childList = matchSelection("", []string{})
46+
info = createPlaceholderFileInfo("", true)
47+
matchName, matchPrefix, childList = matchSelection(info, []string{})
3848
if !expect(true, false) {
3949
t.Error(matchName, matchPrefix, childList)
4050
}
4151

42-
matchName, matchPrefix, childList = matchSelection("", []string{"dir-x"})
52+
info = createPlaceholderFileInfo("", true)
53+
matchName, matchPrefix, childList = matchSelection(info, []string{"dir-x"})
4354
if !expect(false, false) {
4455
t.Error(matchName, matchPrefix, childList)
4556
}
4657

47-
matchName, matchPrefix, childList = matchSelection("dir-a", nil)
58+
info = createPlaceholderFileInfo("dir-a", true)
59+
matchName, matchPrefix, childList = matchSelection(info, nil)
4860
if !expect(true, false) {
4961
t.Error(matchName, matchPrefix, childList)
5062
}
5163

52-
matchName, matchPrefix, childList = matchSelection("dir-a", []string{"dir-x"})
64+
info = createPlaceholderFileInfo("dir-a", true)
65+
matchName, matchPrefix, childList = matchSelection(info, []string{"dir-x"})
5366
if !expect(false, false) {
5467
t.Error(matchName, matchPrefix, childList)
5568
}
5669

57-
matchName, matchPrefix, childList = matchSelection("dir-a", []string{"dir-a"})
70+
info = createPlaceholderFileInfo("dir-a", true)
71+
matchName, matchPrefix, childList = matchSelection(info, []string{"dir-a"})
5872
if !expect(true, false) {
5973
t.Error(matchName, matchPrefix, childList)
6074
}
6175

62-
matchName, matchPrefix, childList = matchSelection("dir-a", []string{"dir-a/dir-a1"})
76+
info = createPlaceholderFileInfo("dir-a", true)
77+
matchName, matchPrefix, childList = matchSelection(info, []string{"dir-a/dir-a1"})
6378
if !expect(false, true, "dir-a1") {
6479
t.Error(matchName, matchPrefix, childList)
6580
}
6681

67-
matchName, matchPrefix, childList = matchSelection("dir-a", []string{"dir-a/dir-a1", "dir-a/dir-a2", "dir-a/dir-a1/dir-a11", "dir-b"})
82+
info = createPlaceholderFileInfo("dir-a", true)
83+
matchName, matchPrefix, childList = matchSelection(info, []string{"dir-a/dir-a1", "dir-a/dir-a2", "dir-a/dir-a1/dir-a11", "dir-b"})
6884
if !expect(false, true, "dir-a1", "dir-a2", "dir-a1/dir-a11") {
6985
t.Error(matchName, matchPrefix, childList)
7086
}
7187

72-
matchName, matchPrefix, childList = matchSelection("dir-a", []string{"dir-a", "dir-a/dir-a1"})
73-
if !expect(true, true, "dir-a1") {
88+
info = createPlaceholderFileInfoNoCase("dir-a", true)
89+
matchName, matchPrefix, childList = matchSelection(info, []string{"Dir-a/dir-a1"})
90+
if !expect(false, true, "dir-a1") {
91+
t.Error(matchName, matchPrefix, childList)
92+
}
93+
94+
info = createPlaceholderFileInfoNoCase("dir-a", true)
95+
matchName, matchPrefix, childList = matchSelection(info, []string{"Dir-a/dir-a1", "dir-a/dir-a2", "dir-a/dir-a1/dir-a11", "dir-b"})
96+
if !expect(false, true, "dir-a1", "dir-a2", "dir-a1/dir-a11") {
7497
t.Error(matchName, matchPrefix, childList)
7598
}
7699
}

src/serverHandler/util.go

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,6 @@ func needResponseBody(method string) bool {
1818
method != http.MethodTrace
1919
}
2020

21-
func containsItem(infos []os.FileInfo, name string) bool {
22-
for i := range infos {
23-
if infos[i].Name() == name {
24-
return true
25-
}
26-
}
27-
return false
28-
}
29-
3021
func getCleanFilePath(requestPath string) (filePath string, ok bool) {
3122
filePath = path.Clean(requestPath)
3223
ok = filePath == path.Base(filePath)
@@ -87,11 +78,42 @@ func createVirtualFileInfo(name string, refItem os.FileInfo, caseSensitive bool)
8778

8879
func isVirtual(info os.FileInfo) bool {
8980
switch info.(type) {
90-
case placeholderFileInfo:
91-
case renamedFileInfo:
92-
case placeholderFileInfoNoCase:
93-
case renamedFileInfoNoCase:
81+
case placeholderFileInfo, renamedFileInfo, placeholderFileInfoNoCase, renamedFileInfoNoCase:
9482
return true
9583
}
9684
return false
9785
}
86+
87+
func isNameCaseSensitive(info os.FileInfo) bool {
88+
switch info.(type) {
89+
case placeholderFileInfoNoCase, renamedFileInfoNoCase:
90+
return false
91+
}
92+
return true
93+
}
94+
95+
func isNameEqualAccurate(a, b string) bool {
96+
return a == b
97+
}
98+
99+
func isNameEqualNoCase(a, b string) bool {
100+
return strings.EqualFold(a, b)
101+
}
102+
103+
func getIsNameEqualFunc(info os.FileInfo) func(a, b string) bool {
104+
if isNameCaseSensitive(info) {
105+
return isNameEqualAccurate
106+
} else {
107+
return isNameEqualNoCase
108+
}
109+
}
110+
111+
func containsItem(infos []os.FileInfo, name string) bool {
112+
for i := range infos {
113+
isNameEqual := getIsNameEqualFunc(infos[i])
114+
if isNameEqual(infos[i].Name(), name) {
115+
return true
116+
}
117+
}
118+
return false
119+
}

src/serverHandler/util_test.go

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package serverHandler
22

3-
import "testing"
3+
import (
4+
"os"
5+
"testing"
6+
)
47

58
func TestGetCleanFilePath(t *testing.T) {
69
var cleanPath string
@@ -71,3 +74,54 @@ func TestGetCleanDirFilePath(t *testing.T) {
7174
t.Error(cleanPath, ok)
7275
}
7376
}
77+
78+
func TestIsVirtual(t *testing.T) {
79+
var info os.FileInfo
80+
81+
info = createPlaceholderFileInfo("foo", true)
82+
if !isVirtual(info) {
83+
t.Error()
84+
}
85+
info = createPlaceholderFileInfoNoCase("foo", true)
86+
if !isVirtual(info) {
87+
t.Error()
88+
}
89+
90+
baseInfo := dummyFileInfo{name: "foo"}
91+
if isVirtual(baseInfo) {
92+
t.Error()
93+
}
94+
95+
info = createRenamedFileInfo("bar", baseInfo)
96+
if !isVirtual(info) {
97+
t.Error()
98+
}
99+
info = createRenamedFileInfoNoCase("bar", baseInfo)
100+
if !isVirtual(info) {
101+
t.Error()
102+
}
103+
}
104+
105+
func TestIsNameCaseSensitive(t *testing.T) {
106+
var info os.FileInfo
107+
108+
info = createPlaceholderFileInfo("foo", true)
109+
if !isNameCaseSensitive(info) {
110+
t.Error()
111+
}
112+
info = createPlaceholderFileInfoNoCase("foo", true)
113+
if isNameCaseSensitive(info) {
114+
t.Error()
115+
}
116+
117+
baseInfo := dummyFileInfo{name: "foo"}
118+
119+
info = createRenamedFileInfo("bar", baseInfo)
120+
if !isNameCaseSensitive(info) {
121+
t.Error()
122+
}
123+
info = createRenamedFileInfoNoCase("bar", baseInfo)
124+
if isNameCaseSensitive(info) {
125+
t.Error()
126+
}
127+
}

test/case/013.bind.upload.bash

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/bin/bash
2+
3+
cleanup() {
4+
rm -f "$fs"/uploaded/2/*.tmp
5+
rm -fr "$fs"/vhost1/[Mm][Yy]*
6+
}
7+
8+
source "$root"/lib.bash
9+
10+
"$ghfs" -l 3003 -r "$fs"/vhost1 --bind :/my/upload:"$fs"/uploaded/2 --upload / --mkdir / &> /dev/null &
11+
sleep 0.05 # wait server ready
12+
cleanup
13+
14+
content='my/upload/uploaded.tmp'
15+
curl_upload_content 'http://127.0.0.1:3003/my/upload?upload' file "$content" uploaded.tmp
16+
uploaded=$(cat "$fs"/uploaded/2/uploaded.tmp)
17+
assert "$uploaded" "$content"
18+
19+
content='MY/Upload/uploaded2.tmp'
20+
curl_upload_content 'http://127.0.0.1:3003/my/upload?upload' file "$content" 'temp/dir/uploaded2.tmp'
21+
uploaded=$(cat "$fs"/uploaded/2/uploaded2.tmp)
22+
assert "$uploaded" "$content"
23+
24+
curl_upload_content 'http://127.0.0.1:3003/?upload' file mycontent My
25+
[ -e "$fs"/vhost1/My ] && fail "$fs/vhost1/My should not exists"
26+
27+
curl_upload_content 'http://127.0.0.1:3003/?upload' file mycontent 'dir/to/My'
28+
[ -e "$fs"/vhost1/My ] && fail "$fs/vhost1/My should not exists"
29+
30+
curl_upload_content 'http://127.0.0.1:3003/?upload' dirfile mycontent 'My/Myfile'
31+
[ -e "$fs"/vhost1/My ] && fail "$fs/vhost1/My should not exists"
32+
33+
curl_upload_content 'http://127.0.0.1:3003/?upload' dirfile mycontent 'My/Mydir/file'
34+
[ -e "$fs"/vhost1/My ] && fail "$fs/vhost1/My should not exists"
35+
36+
cleanup
37+
jobs -p | xargs kill

0 commit comments

Comments
 (0)