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