mirror of
https://github.com/ipfs/kubo.git
synced 2025-08-06 19:44:01 +08:00
157 lines
2.6 KiB
Go
157 lines
2.6 KiB
Go
package commands
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"mime"
|
|
"mime/multipart"
|
|
"net/http"
|
|
)
|
|
|
|
const (
|
|
multipartFormdataType = "multipart/form-data"
|
|
multipartMixedType = "multipart/mixed"
|
|
|
|
contentTypeHeader = "Content-Type"
|
|
)
|
|
|
|
var (
|
|
ErrNotDirectory = errors.New("Couln't call NextFile(), this isn't a directory")
|
|
ErrNotReader = errors.New("This file is a directory, can't use Reader functions")
|
|
)
|
|
|
|
type File interface {
|
|
io.ReadCloser
|
|
FileName() string
|
|
IsDirectory() bool
|
|
NextFile() (File, error)
|
|
}
|
|
|
|
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)
|
|
|
|
var params map[string]string
|
|
var err error
|
|
f.Mediatype, params, err = mime.ParseMediaType(contentType)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if f.IsDirectory() {
|
|
boundary, found := params["boundary"]
|
|
if !found {
|
|
return nil, http.ErrMissingBoundary
|
|
}
|
|
|
|
f.Reader = multipart.NewReader(part, boundary)
|
|
}
|
|
|
|
return f, nil
|
|
}
|
|
|
|
func (f *MultipartFile) IsDirectory() bool {
|
|
return f.Mediatype == multipartFormdataType || f.Mediatype == multipartMixedType
|
|
}
|
|
|
|
func (f *MultipartFile) NextFile() (File, error) {
|
|
if !f.IsDirectory() {
|
|
return nil, ErrNotDirectory
|
|
}
|
|
|
|
part, err := f.Reader.NextPart()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return NewFileFromPart(part)
|
|
}
|
|
|
|
func (f *MultipartFile) FileName() string {
|
|
return f.Part.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()
|
|
}
|
|
|
|
type SliceFile struct {
|
|
Filename string
|
|
Files []File
|
|
}
|
|
|
|
func (f *SliceFile) IsDirectory() bool {
|
|
return true
|
|
}
|
|
|
|
func (f *SliceFile) NextFile() (File, error) {
|
|
if len(f.Files) == 0 {
|
|
return nil, io.EOF
|
|
}
|
|
file := f.Files[0]
|
|
f.Files = f.Files[1:]
|
|
return file, nil
|
|
}
|
|
|
|
func (f *SliceFile) FileName() string {
|
|
return f.Filename
|
|
}
|
|
|
|
func (f *SliceFile) Read(p []byte) (int, error) {
|
|
return 0, ErrNotReader
|
|
}
|
|
|
|
func (f *SliceFile) Close() error {
|
|
return ErrNotReader
|
|
}
|
|
|
|
type ReaderFile struct {
|
|
Filename string
|
|
Reader io.Reader
|
|
}
|
|
|
|
func (f *ReaderFile) IsDirectory() bool {
|
|
return false
|
|
}
|
|
|
|
func (f *ReaderFile) NextFile() (File, error) {
|
|
return nil, ErrNotDirectory
|
|
}
|
|
|
|
func (f *ReaderFile) FileName() string {
|
|
return f.Filename
|
|
}
|
|
|
|
func (f *ReaderFile) Read(p []byte) (int, error) {
|
|
return f.Reader.Read(p)
|
|
}
|
|
|
|
func (f *ReaderFile) Close() error {
|
|
closer, ok := f.Reader.(io.Closer)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return closer.Close()
|
|
}
|