Skip to content
This repository was archived by the owner on Mar 29, 2023. It is now read-only.

Commit da001e4

Browse files
committed
multipart: fix handling of common prefixes
1 parent ea084ca commit da001e4

File tree

2 files changed

+66
-3
lines changed

2 files changed

+66
-3
lines changed

multifilereader_test.go

+40
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,43 @@ func TestOutput(t *testing.T) {
163163
t.Fatal("Expected to get (nil, io.EOF)")
164164
}
165165
}
166+
167+
func TestCommonPrefix(t *testing.T) {
168+
sf := NewMapDirectory(map[string]Node{
169+
"boop": NewMapDirectory(map[string]Node{
170+
"a": NewBytesFile([]byte("bleep")),
171+
"aa": NewBytesFile([]byte("bleep")),
172+
"aaa": NewBytesFile([]byte("bleep")),
173+
}),
174+
})
175+
mfr := NewMultiFileReader(sf, true)
176+
reader, err := NewFileFromPartReader(multipart.NewReader(mfr, mfr.Boundary()), multipartFormdataType)
177+
if err != nil {
178+
t.Fatal(err)
179+
}
180+
181+
CheckDir(t, reader, []Event{
182+
{
183+
kind: TDirStart,
184+
name: "boop",
185+
},
186+
{
187+
kind: TFile,
188+
name: "a",
189+
value: "bleep",
190+
},
191+
{
192+
kind: TFile,
193+
name: "aa",
194+
value: "bleep",
195+
},
196+
{
197+
kind: TFile,
198+
name: "aaa",
199+
value: "bleep",
200+
},
201+
{
202+
kind: TDirEnd,
203+
},
204+
})
205+
}

multipartfile.go

+26-3
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ func (w *multipartWalker) nextFile() (Node, error) {
111111
}, nil
112112
}
113113

114+
// fileName returns a normalized filename from a part.
114115
func fileName(part *multipart.Part) string {
115116
filename := part.FileName()
116117
if escaped, err := url.QueryUnescape(filename); err == nil {
@@ -120,10 +121,32 @@ func fileName(part *multipart.Part) string {
120121
return path.Clean("/" + filename)
121122
}
122123

124+
// dirName appends a slash to the end of the filename, if not present.
125+
// expects a _cleaned_ path.
126+
func dirName(filename string) string {
127+
if !strings.HasSuffix(filename, "/") {
128+
filename += "/"
129+
}
130+
return filename
131+
}
132+
133+
// isDirectory checks if the media type is a valid directory media type.
123134
func isDirectory(mediatype string) bool {
124135
return mediatype == multipartFormdataType || mediatype == applicationDirectory
125136
}
126137

138+
// isChild checks if child is a child of parent directory.
139+
// expects a _cleaned_ path.
140+
func isChild(child, parent string) bool {
141+
return strings.HasPrefix(child, dirName(parent))
142+
}
143+
144+
// makeRelative makes the child path relative to the parent path.
145+
// expects a _cleaned_ path.
146+
func makeRelative(child, parent string) string {
147+
return strings.TrimPrefix(child, dirName(parent))
148+
}
149+
127150
type multipartIterator struct {
128151
f *multipartDirectory
129152

@@ -154,18 +177,18 @@ func (it *multipartIterator) Next() bool {
154177
name := fileName(part)
155178

156179
// Is the file in a different directory?
157-
if !strings.HasPrefix(name, it.f.path) {
180+
if !isChild(name, it.f.path) {
158181
return false
159182
}
160183

161184
// Have we already entered this directory?
162-
if it.curName != "" && strings.HasPrefix(name, path.Join(it.f.path, it.curName)) {
185+
if it.curName != "" && isChild(name, path.Join(it.f.path, it.curName)) {
163186
it.f.walker.consumePart()
164187
continue
165188
}
166189

167190
// Make the path relative to the current directory.
168-
name = strings.TrimLeft(name[len(it.f.path):], "/")
191+
name = makeRelative(name, it.f.path)
169192

170193
// Check if we need to create a fake directory (more than one
171194
// path component).

0 commit comments

Comments
 (0)