/
multipartfile.go
107 lines (87 loc) · 2 KB
/
multipartfile.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package files
import (
"io"
"io/ioutil"
"mime"
"mime/multipart"
"net/url"
)
const (
multipartFormdataType = "multipart/form-data"
multipartMixedType = "multipart/mixed"
applicationDirectory = "application/x-directory"
applicationSymlink = "application/symlink"
contentTypeHeader = "Content-Type"
)
// MultipartFile implements File, and is created from a `multipart.Part`.
// It can be either a directory or file (checked by calling `IsDirectory()`).
type MultipartFile struct {
File
Part *multipart.Part
Reader *multipart.Reader
Mediatype string
}
func NewFileFromPart(part *multipart.Part) (File, error) {
f := &MultipartFile{
Part: part,
}
contentType := part.Header.Get(contentTypeHeader)
if contentType == applicationSymlink {
out, err := ioutil.ReadAll(part)
if err != nil {
return nil, err
}
return &Symlink{
Target: string(out),
name: f.FileName(),
}, nil
}
var err error
f.Mediatype, _, err = mime.ParseMediaType(contentType)
if err != nil {
return nil, err
}
return f, nil
}
func (f *MultipartFile) IsDirectory() bool {
return f.Mediatype == multipartFormdataType || f.Mediatype == applicationDirectory
}
func (f *MultipartFile) NextFile() (File, error) {
if !f.IsDirectory() {
return nil, ErrNotDirectory
}
if f.Reader != nil {
part, err := f.Reader.NextPart()
if err != nil {
return nil, err
}
return NewFileFromPart(part)
}
return nil, io.EOF
}
func (f *MultipartFile) FileName() string {
if f == nil || f.Part == nil {
return ""
}
filename, err := url.QueryUnescape(f.Part.FileName())
if err != nil {
// if there is a unescape error, just treat the name as unescaped
return f.Part.FileName()
}
return filename
}
func (f *MultipartFile) FullPath() string {
return f.FileName()
}
func (f *MultipartFile) Read(p []byte) (int, error) {
if f.IsDirectory() {
return 0, ErrNotReader
}
return f.Part.Read(p)
}
func (f *MultipartFile) Close() error {
if f.IsDirectory() {
return ErrNotReader
}
return f.Part.Close()
}