123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- package dara
- import (
- "bytes"
- "fmt"
- "io"
- "math/rand"
- "net/url"
- "strings"
- )
- type FileField struct {
- Filename *string `json:"filename" xml:"filename" require:"true"`
- ContentType *string `json:"content-type" xml:"content-type" require:"true"`
- Content io.Reader `json:"content" xml:"content" require:"true"`
- }
- func (s *FileField) SetFilename(v string) *FileField {
- s.Filename = &v
- return s
- }
- func (s *FileField) SetContentType(v string) *FileField {
- s.ContentType = &v
- return s
- }
- func (s *FileField) SetContent(v io.Reader) *FileField {
- s.Content = v
- return s
- }
- type FileFormReader struct {
- formFiles []*formFile
- formField io.Reader
- index int
- streaming bool
- ifField bool
- }
- type formFile struct {
- StartField io.Reader
- EndField io.Reader
- File io.Reader
- start bool
- end bool
- }
- const numBytes = "1234567890"
- func GetBoundary() string {
- b := make([]byte, 14)
- for i := range b {
- b[i] = numBytes[rand.Intn(len(numBytes))]
- }
- return string(b)
- }
- func ToFileForm(body map[string]interface{}, boundary string) io.Reader {
- out := bytes.NewBuffer(nil)
- line := "--" + boundary + "\r\n"
- forms := make(map[string]string)
- files := make(map[string]map[string]interface{})
- for key, value := range body {
- switch value.(type) {
- case *FileField:
- if val, ok := value.(*FileField); ok {
- out := make(map[string]interface{})
- out["filename"] = StringValue(val.Filename)
- out["content-type"] = StringValue(val.ContentType)
- out["content"] = val.Content
- files[key] = out
- }
- case map[string]interface{}:
- if val, ok := value.(map[string]interface{}); ok {
- files[key] = val
- }
- default:
- forms[key] = fmt.Sprintf("%v", value)
- }
- }
- for key, value := range forms {
- if value != "" {
- out.Write([]byte(line))
- out.Write([]byte("Content-Disposition: form-data; name=\"" + key + "\"" + "\r\n\r\n"))
- out.Write([]byte(value + "\r\n"))
- }
- }
- formFiles := make([]*formFile, 0)
- for key, value := range files {
- var file io.Reader
- start := line
- start += "Content-Disposition: form-data; name=\"" + key + "\"; filename=\"" + value["filename"].(string) + "\"\r\n"
- start += "Content-Type: " + value["content-type"].(string) + "\r\n\r\n"
- if content, ok := value["content"].(io.Reader); ok {
- file = content
- } else {
- file = strings.NewReader("")
- }
- formFile := &formFile{
- File: file,
- start: true,
- StartField: strings.NewReader(start),
- }
- if len(files) == len(formFiles)+1 {
- end := "\r\n\r\n--" + boundary + "--\r\n"
- formFile.EndField = strings.NewReader(end)
- } else {
- formFile.EndField = strings.NewReader("\r\n\r\n")
- }
- formFiles = append(formFiles, formFile)
- }
- return &FileFormReader{
- formFiles: formFiles,
- formField: out,
- ifField: true,
- }
- }
- func (f *FileFormReader) Read(p []byte) (n int, err error) {
- if f.ifField {
- n, err = f.formField.Read(p)
- if err != nil && err != io.EOF {
- return n, err
- } else if err == io.EOF {
- err = nil
- f.ifField = false
- f.streaming = true
- }
- } else if f.streaming {
- form := f.formFiles[f.index]
- if form.start {
- n, err = form.StartField.Read(p)
- if err != nil && err != io.EOF {
- return n, err
- } else if err == io.EOF {
- err = nil
- form.start = false
- }
- } else if form.end {
- n, err = form.EndField.Read(p)
- if err != nil && err != io.EOF {
- return n, err
- } else if err == io.EOF {
- f.index++
- form.end = false
- if f.index < len(f.formFiles) {
- err = nil
- }
- }
- } else {
- n, err = form.File.Read(p)
- if err != nil && err != io.EOF {
- return n, err
- } else if err == io.EOF {
- err = nil
- form.end = true
- }
- }
- }
- return n, err
- }
- func ToFormString(a map[string]interface{}) string {
- if a == nil {
- return ""
- }
- res := ""
- urlEncoder := url.Values{}
- for key, value := range a {
- v := fmt.Sprintf("%v", value)
- urlEncoder.Add(key, v)
- }
- res = urlEncoder.Encode()
- return res
- }
|